Compare commits
6 commits
Author | SHA1 | Date | |
---|---|---|---|
ef25273b20 | |||
9869f5abbf | |||
0d6914d14d | |||
6b7949e1a1 | |||
604a1378b7 | |||
0394c10616 |
15 changed files with 1742 additions and 1263 deletions
1062
delojza.py
Executable file
1062
delojza.py
Executable file
File diff suppressed because it is too large
Load diff
27
markov.py
Normal file
27
markov.py
Normal file
|
@ -0,0 +1,27 @@
|
|||
import logging
|
||||
from typing import cast
|
||||
|
||||
import markovify
|
||||
from _typeshed import StrPath
|
||||
from markovify import Text
|
||||
|
||||
|
||||
class MarkovBlabberer:
|
||||
def __init__(self, filepath: StrPath):
|
||||
self.logger = logging.getLogger("markov")
|
||||
self.filepath = filepath
|
||||
|
||||
with open(filepath) as f:
|
||||
text = f.read()
|
||||
self.markov: Text = markovify.NewlineText(text.lower())
|
||||
self.logger.info("Sentence of the day: " + self.make_sentence())
|
||||
|
||||
def make_sentence(self, tries: int = 100):
|
||||
return self.markov.make_sentence(tries=tries) or "???"
|
||||
|
||||
def add_to_corpus(self, text: str):
|
||||
text = text.lower()
|
||||
new_sentence = markovify.NewlineText(text)
|
||||
self.markov = cast(Text, markovify.combine([self.markov, new_sentence]))
|
||||
with open(self.filepath, "a") as f:
|
||||
f.write(text + "\n")
|
611
poetry.lock
generated
Normal file
611
poetry.lock
generated
Normal file
|
@ -0,0 +1,611 @@
|
|||
[[package]]
|
||||
name = "apscheduler"
|
||||
version = "3.6.3"
|
||||
description = "In-process task scheduler with Cron-like capabilities"
|
||||
category = "main"
|
||||
optional = false
|
||||
python-versions = "*"
|
||||
|
||||
[package.dependencies]
|
||||
pytz = "*"
|
||||
six = ">=1.4.0"
|
||||
tzlocal = ">=1.2"
|
||||
|
||||
[package.extras]
|
||||
asyncio = ["trollius"]
|
||||
doc = ["sphinx", "sphinx-rtd-theme"]
|
||||
gevent = ["gevent"]
|
||||
mongodb = ["pymongo (>=2.8)"]
|
||||
redis = ["redis (>=3.0)"]
|
||||
rethinkdb = ["rethinkdb (>=2.4.0)"]
|
||||
sqlalchemy = ["sqlalchemy (>=0.8)"]
|
||||
testing = ["pytest", "pytest-cov", "pytest-tornado5", "mock", "pytest-asyncio (<0.6)", "pytest-asyncio"]
|
||||
tornado = ["tornado (>=4.3)"]
|
||||
twisted = ["twisted"]
|
||||
zookeeper = ["kazoo"]
|
||||
|
||||
[[package]]
|
||||
name = "audioread"
|
||||
version = "2.1.9"
|
||||
description = "multi-library, cross-platform audio decoding"
|
||||
category = "main"
|
||||
optional = false
|
||||
python-versions = "*"
|
||||
|
||||
[[package]]
|
||||
name = "backports.zoneinfo"
|
||||
version = "0.2.1"
|
||||
description = "Backport of the standard library zoneinfo module"
|
||||
category = "main"
|
||||
optional = false
|
||||
python-versions = ">=3.6"
|
||||
|
||||
[package.extras]
|
||||
tzdata = ["tzdata"]
|
||||
|
||||
[[package]]
|
||||
name = "black"
|
||||
version = "21.9b0"
|
||||
description = "The uncompromising code formatter."
|
||||
category = "dev"
|
||||
optional = false
|
||||
python-versions = ">=3.6.2"
|
||||
|
||||
[package.dependencies]
|
||||
click = ">=7.1.2"
|
||||
mypy-extensions = ">=0.4.3"
|
||||
pathspec = ">=0.9.0,<1"
|
||||
platformdirs = ">=2"
|
||||
regex = ">=2020.1.8"
|
||||
tomli = ">=0.2.6,<2.0.0"
|
||||
typing-extensions = [
|
||||
{version = ">=3.10.0.0", markers = "python_version < \"3.10\""},
|
||||
{version = "!=3.10.0.1", markers = "python_version >= \"3.10\""},
|
||||
]
|
||||
|
||||
[package.extras]
|
||||
colorama = ["colorama (>=0.4.3)"]
|
||||
d = ["aiohttp (>=3.6.0)", "aiohttp-cors (>=0.4.0)"]
|
||||
jupyter = ["ipython (>=7.8.0)", "tokenize-rt (>=3.2.0)"]
|
||||
python2 = ["typed-ast (>=1.4.2)"]
|
||||
uvloop = ["uvloop (>=0.15.2)"]
|
||||
|
||||
[[package]]
|
||||
name = "cachetools"
|
||||
version = "4.2.2"
|
||||
description = "Extensible memoizing collections and decorators"
|
||||
category = "main"
|
||||
optional = false
|
||||
python-versions = "~=3.5"
|
||||
|
||||
[[package]]
|
||||
name = "certifi"
|
||||
version = "2021.5.30"
|
||||
description = "Python package for providing Mozilla's CA Bundle."
|
||||
category = "main"
|
||||
optional = false
|
||||
python-versions = "*"
|
||||
|
||||
[[package]]
|
||||
name = "charset-normalizer"
|
||||
version = "2.0.4"
|
||||
description = "The Real First Universal Charset Detector. Open, modern and actively maintained alternative to Chardet."
|
||||
category = "main"
|
||||
optional = false
|
||||
python-versions = ">=3.5.0"
|
||||
|
||||
[package.extras]
|
||||
unicode_backport = ["unicodedata2"]
|
||||
|
||||
[[package]]
|
||||
name = "click"
|
||||
version = "8.0.1"
|
||||
description = "Composable command line interface toolkit"
|
||||
category = "dev"
|
||||
optional = false
|
||||
python-versions = ">=3.6"
|
||||
|
||||
[package.dependencies]
|
||||
colorama = {version = "*", markers = "platform_system == \"Windows\""}
|
||||
|
||||
[[package]]
|
||||
name = "colorama"
|
||||
version = "0.4.4"
|
||||
description = "Cross-platform colored terminal text."
|
||||
category = "dev"
|
||||
optional = false
|
||||
python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*"
|
||||
|
||||
[[package]]
|
||||
name = "filetype"
|
||||
version = "1.0.7"
|
||||
description = "Infer file type and MIME type of any file/buffer. No external dependencies."
|
||||
category = "main"
|
||||
optional = false
|
||||
python-versions = "*"
|
||||
|
||||
[[package]]
|
||||
name = "future"
|
||||
version = "0.18.2"
|
||||
description = "Clean single-source support for Python 3 and 2"
|
||||
category = "main"
|
||||
optional = false
|
||||
python-versions = ">=2.6, !=3.0.*, !=3.1.*, !=3.2.*"
|
||||
|
||||
[[package]]
|
||||
name = "idna"
|
||||
version = "3.2"
|
||||
description = "Internationalized Domain Names in Applications (IDNA)"
|
||||
category = "main"
|
||||
optional = false
|
||||
python-versions = ">=3.5"
|
||||
|
||||
[[package]]
|
||||
name = "markovify"
|
||||
version = "0.9.3"
|
||||
description = "A simple, extensible Markov chain generator. Uses include generating random semi-plausible sentences based on an existing text."
|
||||
category = "main"
|
||||
optional = false
|
||||
python-versions = "*"
|
||||
|
||||
[package.dependencies]
|
||||
unidecode = "*"
|
||||
|
||||
[[package]]
|
||||
name = "mutagen"
|
||||
version = "1.45.1"
|
||||
description = "read and write audio tags for many formats"
|
||||
category = "main"
|
||||
optional = false
|
||||
python-versions = ">=3.5, <4"
|
||||
|
||||
[[package]]
|
||||
name = "mypy-extensions"
|
||||
version = "0.4.3"
|
||||
description = "Experimental type system extensions for programs checked with the mypy typechecker."
|
||||
category = "dev"
|
||||
optional = false
|
||||
python-versions = "*"
|
||||
|
||||
[[package]]
|
||||
name = "oauthlib"
|
||||
version = "3.1.1"
|
||||
description = "A generic, spec-compliant, thorough implementation of the OAuth request-signing logic"
|
||||
category = "main"
|
||||
optional = false
|
||||
python-versions = ">=3.6"
|
||||
|
||||
[package.extras]
|
||||
rsa = ["cryptography (>=3.0.0,<4)"]
|
||||
signals = ["blinker (>=1.4.0)"]
|
||||
signedtoken = ["cryptography (>=3.0.0,<4)", "pyjwt (>=2.0.0,<3)"]
|
||||
|
||||
[[package]]
|
||||
name = "pathspec"
|
||||
version = "0.9.0"
|
||||
description = "Utility library for gitignore style pattern matching of file paths."
|
||||
category = "dev"
|
||||
optional = false
|
||||
python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,>=2.7"
|
||||
|
||||
[[package]]
|
||||
name = "platformdirs"
|
||||
version = "2.3.0"
|
||||
description = "A small Python module for determining appropriate platform-specific dirs, e.g. a \"user data dir\"."
|
||||
category = "dev"
|
||||
optional = false
|
||||
python-versions = ">=3.6"
|
||||
|
||||
[package.extras]
|
||||
docs = ["Sphinx (>=4)", "furo (>=2021.7.5b38)", "proselint (>=0.10.2)", "sphinx-autodoc-typehints (>=1.12)"]
|
||||
test = ["appdirs (==1.4.4)", "pytest (>=6)", "pytest-cov (>=2.7)", "pytest-mock (>=3.6)"]
|
||||
|
||||
[[package]]
|
||||
name = "pyacoustid"
|
||||
version = "1.2.2"
|
||||
description = "bindings for Chromaprint acoustic fingerprinting and the Acoustid API"
|
||||
category = "main"
|
||||
optional = false
|
||||
python-versions = "*"
|
||||
|
||||
[package.dependencies]
|
||||
audioread = "*"
|
||||
requests = "*"
|
||||
|
||||
[[package]]
|
||||
name = "python-telegram-bot"
|
||||
version = "13.7"
|
||||
description = "We have made you a wrapper you can't refuse"
|
||||
category = "main"
|
||||
optional = false
|
||||
python-versions = ">=3.6"
|
||||
|
||||
[package.dependencies]
|
||||
APScheduler = "3.6.3"
|
||||
cachetools = "4.2.2"
|
||||
certifi = "*"
|
||||
pytz = ">=2018.6"
|
||||
tornado = ">=6.1"
|
||||
|
||||
[package.extras]
|
||||
json = ["ujson"]
|
||||
passport = ["cryptography (!=3.4,!=3.4.1,!=3.4.2,!=3.4.3)"]
|
||||
socks = ["pysocks"]
|
||||
|
||||
[[package]]
|
||||
name = "pytumblr"
|
||||
version = "0.1.0"
|
||||
description = "A Python API v2 wrapper for Tumblr"
|
||||
category = "main"
|
||||
optional = false
|
||||
python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*"
|
||||
|
||||
[package.dependencies]
|
||||
future = "*"
|
||||
requests-oauthlib = "*"
|
||||
|
||||
[[package]]
|
||||
name = "pytz"
|
||||
version = "2021.1"
|
||||
description = "World timezone definitions, modern and historical"
|
||||
category = "main"
|
||||
optional = false
|
||||
python-versions = "*"
|
||||
|
||||
[[package]]
|
||||
name = "regex"
|
||||
version = "2021.8.28"
|
||||
description = "Alternative regular expression module, to replace re."
|
||||
category = "dev"
|
||||
optional = false
|
||||
python-versions = "*"
|
||||
|
||||
[[package]]
|
||||
name = "requests"
|
||||
version = "2.26.0"
|
||||
description = "Python HTTP for Humans."
|
||||
category = "main"
|
||||
optional = false
|
||||
python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*, !=3.5.*"
|
||||
|
||||
[package.dependencies]
|
||||
certifi = ">=2017.4.17"
|
||||
charset-normalizer = {version = ">=2.0.0,<2.1.0", markers = "python_version >= \"3\""}
|
||||
idna = {version = ">=2.5,<4", markers = "python_version >= \"3\""}
|
||||
urllib3 = ">=1.21.1,<1.27"
|
||||
|
||||
[package.extras]
|
||||
socks = ["PySocks (>=1.5.6,!=1.5.7)", "win-inet-pton"]
|
||||
use_chardet_on_py3 = ["chardet (>=3.0.2,<5)"]
|
||||
|
||||
[[package]]
|
||||
name = "requests-oauthlib"
|
||||
version = "1.3.0"
|
||||
description = "OAuthlib authentication support for Requests."
|
||||
category = "main"
|
||||
optional = false
|
||||
python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*"
|
||||
|
||||
[package.dependencies]
|
||||
oauthlib = ">=3.0.0"
|
||||
requests = ">=2.0.0"
|
||||
|
||||
[package.extras]
|
||||
rsa = ["oauthlib[signedtoken] (>=3.0.0)"]
|
||||
|
||||
[[package]]
|
||||
name = "six"
|
||||
version = "1.16.0"
|
||||
description = "Python 2 and 3 compatibility utilities"
|
||||
category = "main"
|
||||
optional = false
|
||||
python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*"
|
||||
|
||||
[[package]]
|
||||
name = "tomli"
|
||||
version = "1.2.1"
|
||||
description = "A lil' TOML parser"
|
||||
category = "dev"
|
||||
optional = false
|
||||
python-versions = ">=3.6"
|
||||
|
||||
[[package]]
|
||||
name = "tornado"
|
||||
version = "6.1"
|
||||
description = "Tornado is a Python web framework and asynchronous networking library, originally developed at FriendFeed."
|
||||
category = "main"
|
||||
optional = false
|
||||
python-versions = ">= 3.5"
|
||||
|
||||
[[package]]
|
||||
name = "typing-extensions"
|
||||
version = "3.10.0.2"
|
||||
description = "Backported and Experimental Type Hints for Python 3.5+"
|
||||
category = "dev"
|
||||
optional = false
|
||||
python-versions = "*"
|
||||
|
||||
[[package]]
|
||||
name = "tzdata"
|
||||
version = "2021.1"
|
||||
description = "Provider of IANA time zone data"
|
||||
category = "main"
|
||||
optional = false
|
||||
python-versions = ">=2"
|
||||
|
||||
[[package]]
|
||||
name = "tzlocal"
|
||||
version = "3.0"
|
||||
description = "tzinfo object for the local timezone"
|
||||
category = "main"
|
||||
optional = false
|
||||
python-versions = ">=3.6"
|
||||
|
||||
[package.dependencies]
|
||||
"backports.zoneinfo" = {version = "*", markers = "python_version < \"3.9\""}
|
||||
tzdata = {version = "*", markers = "platform_system == \"Windows\""}
|
||||
|
||||
[package.extras]
|
||||
test = ["pytest-mock (>=3.3)", "pytest (>=4.3)"]
|
||||
|
||||
[[package]]
|
||||
name = "unidecode"
|
||||
version = "1.3.1"
|
||||
description = "ASCII transliterations of Unicode text"
|
||||
category = "main"
|
||||
optional = false
|
||||
python-versions = ">=3.5"
|
||||
|
||||
[[package]]
|
||||
name = "urllib3"
|
||||
version = "1.26.6"
|
||||
description = "HTTP library with thread-safe connection pooling, file post, and more."
|
||||
category = "main"
|
||||
optional = false
|
||||
python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*, <4"
|
||||
|
||||
[package.extras]
|
||||
brotli = ["brotlipy (>=0.6.0)"]
|
||||
secure = ["pyOpenSSL (>=0.14)", "cryptography (>=1.3.4)", "idna (>=2.0.0)", "certifi", "ipaddress"]
|
||||
socks = ["PySocks (>=1.5.6,!=1.5.7,<2.0)"]
|
||||
|
||||
[[package]]
|
||||
name = "youtube-dl"
|
||||
version = "2021.6.6"
|
||||
description = "YouTube video downloader"
|
||||
category = "main"
|
||||
optional = false
|
||||
python-versions = "*"
|
||||
|
||||
[metadata]
|
||||
lock-version = "1.1"
|
||||
python-versions = "^3.8"
|
||||
content-hash = "3929d6d1ac1d9d4a4a83faf3bea4cfdf9ff44ad31a4dedf7e929d69cb67c7c6a"
|
||||
|
||||
[metadata.files]
|
||||
apscheduler = [
|
||||
{file = "APScheduler-3.6.3-py2.py3-none-any.whl", hash = "sha256:e8b1ecdb4c7cb2818913f766d5898183c7cb8936680710a4d3a966e02262e526"},
|
||||
{file = "APScheduler-3.6.3.tar.gz", hash = "sha256:3bb5229eed6fbbdafc13ce962712ae66e175aa214c69bed35a06bffcf0c5e244"},
|
||||
]
|
||||
audioread = [
|
||||
{file = "audioread-2.1.9.tar.gz", hash = "sha256:a3480e42056c8e80a8192a54f6729a280ef66d27782ee11cbd63e9d4d1523089"},
|
||||
]
|
||||
"backports.zoneinfo" = [
|
||||
{file = "backports.zoneinfo-0.2.1-cp36-cp36m-macosx_10_14_x86_64.whl", hash = "sha256:da6013fd84a690242c310d77ddb8441a559e9cb3d3d59ebac9aca1a57b2e18bc"},
|
||||
{file = "backports.zoneinfo-0.2.1-cp36-cp36m-manylinux1_i686.whl", hash = "sha256:89a48c0d158a3cc3f654da4c2de1ceba85263fafb861b98b59040a5086259722"},
|
||||
{file = "backports.zoneinfo-0.2.1-cp36-cp36m-manylinux1_x86_64.whl", hash = "sha256:1c5742112073a563c81f786e77514969acb58649bcdf6cdf0b4ed31a348d4546"},
|
||||
{file = "backports.zoneinfo-0.2.1-cp36-cp36m-win32.whl", hash = "sha256:e8236383a20872c0cdf5a62b554b27538db7fa1bbec52429d8d106effbaeca08"},
|
||||
{file = "backports.zoneinfo-0.2.1-cp36-cp36m-win_amd64.whl", hash = "sha256:8439c030a11780786a2002261569bdf362264f605dfa4d65090b64b05c9f79a7"},
|
||||
{file = "backports.zoneinfo-0.2.1-cp37-cp37m-macosx_10_14_x86_64.whl", hash = "sha256:f04e857b59d9d1ccc39ce2da1021d196e47234873820cbeaad210724b1ee28ac"},
|
||||
{file = "backports.zoneinfo-0.2.1-cp37-cp37m-manylinux1_i686.whl", hash = "sha256:17746bd546106fa389c51dbea67c8b7c8f0d14b5526a579ca6ccf5ed72c526cf"},
|
||||
{file = "backports.zoneinfo-0.2.1-cp37-cp37m-manylinux1_x86_64.whl", hash = "sha256:5c144945a7752ca544b4b78c8c41544cdfaf9786f25fe5ffb10e838e19a27570"},
|
||||
{file = "backports.zoneinfo-0.2.1-cp37-cp37m-win32.whl", hash = "sha256:e55b384612d93be96506932a786bbcde5a2db7a9e6a4bb4bffe8b733f5b9036b"},
|
||||
{file = "backports.zoneinfo-0.2.1-cp37-cp37m-win_amd64.whl", hash = "sha256:a76b38c52400b762e48131494ba26be363491ac4f9a04c1b7e92483d169f6582"},
|
||||
{file = "backports.zoneinfo-0.2.1-cp38-cp38-macosx_10_14_x86_64.whl", hash = "sha256:8961c0f32cd0336fb8e8ead11a1f8cd99ec07145ec2931122faaac1c8f7fd987"},
|
||||
{file = "backports.zoneinfo-0.2.1-cp38-cp38-manylinux1_i686.whl", hash = "sha256:e81b76cace8eda1fca50e345242ba977f9be6ae3945af8d46326d776b4cf78d1"},
|
||||
{file = "backports.zoneinfo-0.2.1-cp38-cp38-manylinux1_x86_64.whl", hash = "sha256:7b0a64cda4145548fed9efc10322770f929b944ce5cee6c0dfe0c87bf4c0c8c9"},
|
||||
{file = "backports.zoneinfo-0.2.1-cp38-cp38-win32.whl", hash = "sha256:1b13e654a55cd45672cb54ed12148cd33628f672548f373963b0bff67b217328"},
|
||||
{file = "backports.zoneinfo-0.2.1-cp38-cp38-win_amd64.whl", hash = "sha256:4a0f800587060bf8880f954dbef70de6c11bbe59c673c3d818921f042f9954a6"},
|
||||
{file = "backports.zoneinfo-0.2.1.tar.gz", hash = "sha256:fadbfe37f74051d024037f223b8e001611eac868b5c5b06144ef4d8b799862f2"},
|
||||
]
|
||||
black = [
|
||||
{file = "black-21.9b0-py3-none-any.whl", hash = "sha256:380f1b5da05e5a1429225676655dddb96f5ae8c75bdf91e53d798871b902a115"},
|
||||
{file = "black-21.9b0.tar.gz", hash = "sha256:7de4cfc7eb6b710de325712d40125689101d21d25283eed7e9998722cf10eb91"},
|
||||
]
|
||||
cachetools = [
|
||||
{file = "cachetools-4.2.2-py3-none-any.whl", hash = "sha256:2cc0b89715337ab6dbba85b5b50effe2b0c74e035d83ee8ed637cf52f12ae001"},
|
||||
{file = "cachetools-4.2.2.tar.gz", hash = "sha256:61b5ed1e22a0924aed1d23b478f37e8d52549ff8a961de2909c69bf950020cff"},
|
||||
]
|
||||
certifi = [
|
||||
{file = "certifi-2021.5.30-py2.py3-none-any.whl", hash = "sha256:50b1e4f8446b06f41be7dd6338db18e0990601dce795c2b1686458aa7e8fa7d8"},
|
||||
{file = "certifi-2021.5.30.tar.gz", hash = "sha256:2bbf76fd432960138b3ef6dda3dde0544f27cbf8546c458e60baf371917ba9ee"},
|
||||
]
|
||||
charset-normalizer = [
|
||||
{file = "charset-normalizer-2.0.4.tar.gz", hash = "sha256:f23667ebe1084be45f6ae0538e4a5a865206544097e4e8bbcacf42cd02a348f3"},
|
||||
{file = "charset_normalizer-2.0.4-py3-none-any.whl", hash = "sha256:0c8911edd15d19223366a194a513099a302055a962bca2cec0f54b8b63175d8b"},
|
||||
]
|
||||
click = [
|
||||
{file = "click-8.0.1-py3-none-any.whl", hash = "sha256:fba402a4a47334742d782209a7c79bc448911afe1149d07bdabdf480b3e2f4b6"},
|
||||
{file = "click-8.0.1.tar.gz", hash = "sha256:8c04c11192119b1ef78ea049e0a6f0463e4c48ef00a30160c704337586f3ad7a"},
|
||||
]
|
||||
colorama = [
|
||||
{file = "colorama-0.4.4-py2.py3-none-any.whl", hash = "sha256:9f47eda37229f68eee03b24b9748937c7dc3868f906e8ba69fbcbdd3bc5dc3e2"},
|
||||
{file = "colorama-0.4.4.tar.gz", hash = "sha256:5941b2b48a20143d2267e95b1c2a7603ce057ee39fd88e7329b0c292aa16869b"},
|
||||
]
|
||||
filetype = [
|
||||
{file = "filetype-1.0.7-py2.py3-none-any.whl", hash = "sha256:353369948bb1c09b8b3ea3d78390b5586e9399bff9aab894a1dff954e31a66f6"},
|
||||
{file = "filetype-1.0.7.tar.gz", hash = "sha256:da393ece8d98b47edf2dd5a85a2c8733e44b769e32c71af4cd96ed8d38d96aa7"},
|
||||
]
|
||||
future = [
|
||||
{file = "future-0.18.2.tar.gz", hash = "sha256:b1bead90b70cf6ec3f0710ae53a525360fa360d306a86583adc6bf83a4db537d"},
|
||||
]
|
||||
idna = [
|
||||
{file = "idna-3.2-py3-none-any.whl", hash = "sha256:14475042e284991034cb48e06f6851428fb14c4dc953acd9be9a5e95c7b6dd7a"},
|
||||
{file = "idna-3.2.tar.gz", hash = "sha256:467fbad99067910785144ce333826c71fb0e63a425657295239737f7ecd125f3"},
|
||||
]
|
||||
markovify = [
|
||||
{file = "markovify-0.9.3.tar.gz", hash = "sha256:e31c6fcdf4ed12c8e00e39df735ffa0d5546f7515ff4c32e4e0ae23c41f9cba9"},
|
||||
]
|
||||
mutagen = [
|
||||
{file = "mutagen-1.45.1-py3-none-any.whl", hash = "sha256:9c9f243fcec7f410f138cb12c21c84c64fde4195481a30c9bfb05b5f003adfed"},
|
||||
{file = "mutagen-1.45.1.tar.gz", hash = "sha256:6397602efb3c2d7baebd2166ed85731ae1c1d475abca22090b7141ff5034b3e1"},
|
||||
]
|
||||
mypy-extensions = [
|
||||
{file = "mypy_extensions-0.4.3-py2.py3-none-any.whl", hash = "sha256:090fedd75945a69ae91ce1303b5824f428daf5a028d2f6ab8a299250a846f15d"},
|
||||
{file = "mypy_extensions-0.4.3.tar.gz", hash = "sha256:2d82818f5bb3e369420cb3c4060a7970edba416647068eb4c5343488a6c604a8"},
|
||||
]
|
||||
oauthlib = [
|
||||
{file = "oauthlib-3.1.1-py2.py3-none-any.whl", hash = "sha256:42bf6354c2ed8c6acb54d971fce6f88193d97297e18602a3a886603f9d7730cc"},
|
||||
{file = "oauthlib-3.1.1.tar.gz", hash = "sha256:8f0215fcc533dd8dd1bee6f4c412d4f0cd7297307d43ac61666389e3bc3198a3"},
|
||||
]
|
||||
pathspec = [
|
||||
{file = "pathspec-0.9.0-py2.py3-none-any.whl", hash = "sha256:7d15c4ddb0b5c802d161efc417ec1a2558ea2653c2e8ad9c19098201dc1c993a"},
|
||||
{file = "pathspec-0.9.0.tar.gz", hash = "sha256:e564499435a2673d586f6b2130bb5b95f04a3ba06f81b8f895b651a3c76aabb1"},
|
||||
]
|
||||
platformdirs = [
|
||||
{file = "platformdirs-2.3.0-py3-none-any.whl", hash = "sha256:8003ac87717ae2c7ee1ea5a84a1a61e87f3fbd16eb5aadba194ea30a9019f648"},
|
||||
{file = "platformdirs-2.3.0.tar.gz", hash = "sha256:15b056538719b1c94bdaccb29e5f81879c7f7f0f4a153f46086d155dffcd4f0f"},
|
||||
]
|
||||
pyacoustid = [
|
||||
{file = "pyacoustid-1.2.2.tar.gz", hash = "sha256:c279d9c30a7f481f1420fc37db65833b5f9816cd364dc2acaa93a11c482d4141"},
|
||||
]
|
||||
python-telegram-bot = [
|
||||
{file = "python-telegram-bot-13.7.tar.gz", hash = "sha256:24df75459e335b96baffa6991679f844bd426978af5a69ca419a0ac43a40602c"},
|
||||
{file = "python_telegram_bot-13.7-py3-none-any.whl", hash = "sha256:3bf210862744068aa789d5110f8e3a00d98912ce50863384836440a18abf76b5"},
|
||||
]
|
||||
pytumblr = [
|
||||
{file = "PyTumblr-0.1.0-py2.py3-none-any.whl", hash = "sha256:a3774d3978bcff2db98f36a2e5d17bb8496ac21157b1b518089adad86d0dca72"},
|
||||
{file = "PyTumblr-0.1.0.tar.gz", hash = "sha256:eaa4d98217df7ab6392fa5d8801f4a2bdcba35bf0fd49328aa3c98e3b231b6f2"},
|
||||
]
|
||||
pytz = [
|
||||
{file = "pytz-2021.1-py2.py3-none-any.whl", hash = "sha256:eb10ce3e7736052ed3623d49975ce333bcd712c7bb19a58b9e2089d4057d0798"},
|
||||
{file = "pytz-2021.1.tar.gz", hash = "sha256:83a4a90894bf38e243cf052c8b58f381bfe9a7a483f6a9cab140bc7f702ac4da"},
|
||||
]
|
||||
regex = [
|
||||
{file = "regex-2021.8.28-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:9d05ad5367c90814099000442b2125535e9d77581855b9bee8780f1b41f2b1a2"},
|
||||
{file = "regex-2021.8.28-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f3bf1bc02bc421047bfec3343729c4bbbea42605bcfd6d6bfe2c07ade8b12d2a"},
|
||||
{file = "regex-2021.8.28-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:5f6a808044faae658f546dd5f525e921de9fa409de7a5570865467f03a626fc0"},
|
||||
{file = "regex-2021.8.28-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:a617593aeacc7a691cc4af4a4410031654f2909053bd8c8e7db837f179a630eb"},
|
||||
{file = "regex-2021.8.28-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:79aef6b5cd41feff359acaf98e040844613ff5298d0d19c455b3d9ae0bc8c35a"},
|
||||
{file = "regex-2021.8.28-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:0fc1f8f06977c2d4f5e3d3f0d4a08089be783973fc6b6e278bde01f0544ff308"},
|
||||
{file = "regex-2021.8.28-cp310-cp310-win32.whl", hash = "sha256:6eebf512aa90751d5ef6a7c2ac9d60113f32e86e5687326a50d7686e309f66ed"},
|
||||
{file = "regex-2021.8.28-cp310-cp310-win_amd64.whl", hash = "sha256:ac88856a8cbccfc14f1b2d0b829af354cc1743cb375e7f04251ae73b2af6adf8"},
|
||||
{file = "regex-2021.8.28-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:c206587c83e795d417ed3adc8453a791f6d36b67c81416676cad053b4104152c"},
|
||||
{file = "regex-2021.8.28-cp36-cp36m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e8690ed94481f219a7a967c118abaf71ccc440f69acd583cab721b90eeedb77c"},
|
||||
{file = "regex-2021.8.28-cp36-cp36m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:328a1fad67445550b982caa2a2a850da5989fd6595e858f02d04636e7f8b0b13"},
|
||||
{file = "regex-2021.8.28-cp36-cp36m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:c7cb4c512d2d3b0870e00fbbac2f291d4b4bf2634d59a31176a87afe2777c6f0"},
|
||||
{file = "regex-2021.8.28-cp36-cp36m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:66256b6391c057305e5ae9209941ef63c33a476b73772ca967d4a2df70520ec1"},
|
||||
{file = "regex-2021.8.28-cp36-cp36m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:8e44769068d33e0ea6ccdf4b84d80c5afffe5207aa4d1881a629cf0ef3ec398f"},
|
||||
{file = "regex-2021.8.28-cp36-cp36m-win32.whl", hash = "sha256:08d74bfaa4c7731b8dac0a992c63673a2782758f7cfad34cf9c1b9184f911354"},
|
||||
{file = "regex-2021.8.28-cp36-cp36m-win_amd64.whl", hash = "sha256:abb48494d88e8a82601af905143e0de838c776c1241d92021e9256d5515b3645"},
|
||||
{file = "regex-2021.8.28-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:b4c220a1fe0d2c622493b0a1fd48f8f991998fb447d3cd368033a4b86cf1127a"},
|
||||
{file = "regex-2021.8.28-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d4a332404baa6665b54e5d283b4262f41f2103c255897084ec8f5487ce7b9e8e"},
|
||||
{file = "regex-2021.8.28-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c61dcc1cf9fd165127a2853e2c31eb4fb961a4f26b394ac9fe5669c7a6592892"},
|
||||
{file = "regex-2021.8.28-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:ee329d0387b5b41a5dddbb6243a21cb7896587a651bebb957e2d2bb8b63c0791"},
|
||||
{file = "regex-2021.8.28-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:f60667673ff9c249709160529ab39667d1ae9fd38634e006bec95611f632e759"},
|
||||
{file = "regex-2021.8.28-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:b844fb09bd9936ed158ff9df0ab601e2045b316b17aa8b931857365ea8586906"},
|
||||
{file = "regex-2021.8.28-cp37-cp37m-win32.whl", hash = "sha256:4cde065ab33bcaab774d84096fae266d9301d1a2f5519d7bd58fc55274afbf7a"},
|
||||
{file = "regex-2021.8.28-cp37-cp37m-win_amd64.whl", hash = "sha256:1413b5022ed6ac0d504ba425ef02549a57d0f4276de58e3ab7e82437892704fc"},
|
||||
{file = "regex-2021.8.28-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:ed4b50355b066796dacdd1cf538f2ce57275d001838f9b132fab80b75e8c84dd"},
|
||||
{file = "regex-2021.8.28-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:28fc475f560d8f67cc8767b94db4c9440210f6958495aeae70fac8faec631797"},
|
||||
{file = "regex-2021.8.28-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:bdc178caebd0f338d57ae445ef8e9b737ddf8fbc3ea187603f65aec5b041248f"},
|
||||
{file = "regex-2021.8.28-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:999ad08220467b6ad4bd3dd34e65329dd5d0df9b31e47106105e407954965256"},
|
||||
{file = "regex-2021.8.28-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:808ee5834e06f57978da3e003ad9d6292de69d2bf6263662a1a8ae30788e080b"},
|
||||
{file = "regex-2021.8.28-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:d5111d4c843d80202e62b4fdbb4920db1dcee4f9366d6b03294f45ed7b18b42e"},
|
||||
{file = "regex-2021.8.28-cp38-cp38-win32.whl", hash = "sha256:473858730ef6d6ff7f7d5f19452184cd0caa062a20047f6d6f3e135a4648865d"},
|
||||
{file = "regex-2021.8.28-cp38-cp38-win_amd64.whl", hash = "sha256:31a99a4796bf5aefc8351e98507b09e1b09115574f7c9dbb9cf2111f7220d2e2"},
|
||||
{file = "regex-2021.8.28-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:04f6b9749e335bb0d2f68c707f23bb1773c3fb6ecd10edf0f04df12a8920d468"},
|
||||
{file = "regex-2021.8.28-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9b006628fe43aa69259ec04ca258d88ed19b64791693df59c422b607b6ece8bb"},
|
||||
{file = "regex-2021.8.28-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:121f4b3185feaade3f85f70294aef3f777199e9b5c0c0245c774ae884b110a2d"},
|
||||
{file = "regex-2021.8.28-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:a577a21de2ef8059b58f79ff76a4da81c45a75fe0bfb09bc8b7bb4293fa18983"},
|
||||
{file = "regex-2021.8.28-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:1743345e30917e8c574f273f51679c294effba6ad372db1967852f12c76759d8"},
|
||||
{file = "regex-2021.8.28-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:e1e8406b895aba6caa63d9fd1b6b1700d7e4825f78ccb1e5260551d168db38ed"},
|
||||
{file = "regex-2021.8.28-cp39-cp39-win32.whl", hash = "sha256:ed283ab3a01d8b53de3a05bfdf4473ae24e43caee7dcb5584e86f3f3e5ab4374"},
|
||||
{file = "regex-2021.8.28-cp39-cp39-win_amd64.whl", hash = "sha256:610b690b406653c84b7cb6091facb3033500ee81089867ee7d59e675f9ca2b73"},
|
||||
{file = "regex-2021.8.28.tar.gz", hash = "sha256:f585cbbeecb35f35609edccb95efd95a3e35824cd7752b586503f7e6087303f1"},
|
||||
]
|
||||
requests = [
|
||||
{file = "requests-2.26.0-py2.py3-none-any.whl", hash = "sha256:6c1246513ecd5ecd4528a0906f910e8f0f9c6b8ec72030dc9fd154dc1a6efd24"},
|
||||
{file = "requests-2.26.0.tar.gz", hash = "sha256:b8aa58f8cf793ffd8782d3d8cb19e66ef36f7aba4353eec859e74678b01b07a7"},
|
||||
]
|
||||
requests-oauthlib = [
|
||||
{file = "requests-oauthlib-1.3.0.tar.gz", hash = "sha256:b4261601a71fd721a8bd6d7aa1cc1d6a8a93b4a9f5e96626f8e4d91e8beeaa6a"},
|
||||
{file = "requests_oauthlib-1.3.0-py2.py3-none-any.whl", hash = "sha256:7f71572defaecd16372f9006f33c2ec8c077c3cfa6f5911a9a90202beb513f3d"},
|
||||
{file = "requests_oauthlib-1.3.0-py3.7.egg", hash = "sha256:fa6c47b933f01060936d87ae9327fead68768b69c6c9ea2109c48be30f2d4dbc"},
|
||||
]
|
||||
six = [
|
||||
{file = "six-1.16.0-py2.py3-none-any.whl", hash = "sha256:8abb2f1d86890a2dfb989f9a77cfcfd3e47c2a354b01111771326f8aa26e0254"},
|
||||
{file = "six-1.16.0.tar.gz", hash = "sha256:1e61c37477a1626458e36f7b1d82aa5c9b094fa4802892072e49de9c60c4c926"},
|
||||
]
|
||||
tomli = [
|
||||
{file = "tomli-1.2.1-py3-none-any.whl", hash = "sha256:8dd0e9524d6f386271a36b41dbf6c57d8e32fd96fd22b6584679dc569d20899f"},
|
||||
{file = "tomli-1.2.1.tar.gz", hash = "sha256:a5b75cb6f3968abb47af1b40c1819dc519ea82bcc065776a866e8d74c5ca9442"},
|
||||
]
|
||||
tornado = [
|
||||
{file = "tornado-6.1-cp35-cp35m-macosx_10_9_x86_64.whl", hash = "sha256:d371e811d6b156d82aa5f9a4e08b58debf97c302a35714f6f45e35139c332e32"},
|
||||
{file = "tornado-6.1-cp35-cp35m-manylinux1_i686.whl", hash = "sha256:0d321a39c36e5f2c4ff12b4ed58d41390460f798422c4504e09eb5678e09998c"},
|
||||
{file = "tornado-6.1-cp35-cp35m-manylinux1_x86_64.whl", hash = "sha256:9de9e5188a782be6b1ce866e8a51bc76a0fbaa0e16613823fc38e4fc2556ad05"},
|
||||
{file = "tornado-6.1-cp35-cp35m-manylinux2010_i686.whl", hash = "sha256:61b32d06ae8a036a6607805e6720ef00a3c98207038444ba7fd3d169cd998910"},
|
||||
{file = "tornado-6.1-cp35-cp35m-manylinux2010_x86_64.whl", hash = "sha256:3e63498f680547ed24d2c71e6497f24bca791aca2fe116dbc2bd0ac7f191691b"},
|
||||
{file = "tornado-6.1-cp35-cp35m-manylinux2014_aarch64.whl", hash = "sha256:6c77c9937962577a6a76917845d06af6ab9197702a42e1346d8ae2e76b5e3675"},
|
||||
{file = "tornado-6.1-cp35-cp35m-win32.whl", hash = "sha256:6286efab1ed6e74b7028327365cf7346b1d777d63ab30e21a0f4d5b275fc17d5"},
|
||||
{file = "tornado-6.1-cp35-cp35m-win_amd64.whl", hash = "sha256:fa2ba70284fa42c2a5ecb35e322e68823288a4251f9ba9cc77be04ae15eada68"},
|
||||
{file = "tornado-6.1-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:0a00ff4561e2929a2c37ce706cb8233b7907e0cdc22eab98888aca5dd3775feb"},
|
||||
{file = "tornado-6.1-cp36-cp36m-manylinux1_i686.whl", hash = "sha256:748290bf9112b581c525e6e6d3820621ff020ed95af6f17fedef416b27ed564c"},
|
||||
{file = "tornado-6.1-cp36-cp36m-manylinux1_x86_64.whl", hash = "sha256:e385b637ac3acaae8022e7e47dfa7b83d3620e432e3ecb9a3f7f58f150e50921"},
|
||||
{file = "tornado-6.1-cp36-cp36m-manylinux2010_i686.whl", hash = "sha256:25ad220258349a12ae87ede08a7b04aca51237721f63b1808d39bdb4b2164558"},
|
||||
{file = "tornado-6.1-cp36-cp36m-manylinux2010_x86_64.whl", hash = "sha256:65d98939f1a2e74b58839f8c4dab3b6b3c1ce84972ae712be02845e65391ac7c"},
|
||||
{file = "tornado-6.1-cp36-cp36m-manylinux2014_aarch64.whl", hash = "sha256:e519d64089b0876c7b467274468709dadf11e41d65f63bba207e04217f47c085"},
|
||||
{file = "tornado-6.1-cp36-cp36m-win32.whl", hash = "sha256:b87936fd2c317b6ee08a5741ea06b9d11a6074ef4cc42e031bc6403f82a32575"},
|
||||
{file = "tornado-6.1-cp36-cp36m-win_amd64.whl", hash = "sha256:cc0ee35043162abbf717b7df924597ade8e5395e7b66d18270116f8745ceb795"},
|
||||
{file = "tornado-6.1-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:7250a3fa399f08ec9cb3f7b1b987955d17e044f1ade821b32e5f435130250d7f"},
|
||||
{file = "tornado-6.1-cp37-cp37m-manylinux1_i686.whl", hash = "sha256:ed3ad863b1b40cd1d4bd21e7498329ccaece75db5a5bf58cd3c9f130843e7102"},
|
||||
{file = "tornado-6.1-cp37-cp37m-manylinux1_x86_64.whl", hash = "sha256:dcef026f608f678c118779cd6591c8af6e9b4155c44e0d1bc0c87c036fb8c8c4"},
|
||||
{file = "tornado-6.1-cp37-cp37m-manylinux2010_i686.whl", hash = "sha256:70dec29e8ac485dbf57481baee40781c63e381bebea080991893cd297742b8fd"},
|
||||
{file = "tornado-6.1-cp37-cp37m-manylinux2010_x86_64.whl", hash = "sha256:d3f7594930c423fd9f5d1a76bee85a2c36fd8b4b16921cae7e965f22575e9c01"},
|
||||
{file = "tornado-6.1-cp37-cp37m-manylinux2014_aarch64.whl", hash = "sha256:3447475585bae2e77ecb832fc0300c3695516a47d46cefa0528181a34c5b9d3d"},
|
||||
{file = "tornado-6.1-cp37-cp37m-win32.whl", hash = "sha256:e7229e60ac41a1202444497ddde70a48d33909e484f96eb0da9baf8dc68541df"},
|
||||
{file = "tornado-6.1-cp37-cp37m-win_amd64.whl", hash = "sha256:cb5ec8eead331e3bb4ce8066cf06d2dfef1bfb1b2a73082dfe8a161301b76e37"},
|
||||
{file = "tornado-6.1-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:20241b3cb4f425e971cb0a8e4ffc9b0a861530ae3c52f2b0434e6c1b57e9fd95"},
|
||||
{file = "tornado-6.1-cp38-cp38-manylinux1_i686.whl", hash = "sha256:c77da1263aa361938476f04c4b6c8916001b90b2c2fdd92d8d535e1af48fba5a"},
|
||||
{file = "tornado-6.1-cp38-cp38-manylinux1_x86_64.whl", hash = "sha256:fba85b6cd9c39be262fcd23865652920832b61583de2a2ca907dbd8e8a8c81e5"},
|
||||
{file = "tornado-6.1-cp38-cp38-manylinux2010_i686.whl", hash = "sha256:1e8225a1070cd8eec59a996c43229fe8f95689cb16e552d130b9793cb570a288"},
|
||||
{file = "tornado-6.1-cp38-cp38-manylinux2010_x86_64.whl", hash = "sha256:d14d30e7f46a0476efb0deb5b61343b1526f73ebb5ed84f23dc794bdb88f9d9f"},
|
||||
{file = "tornado-6.1-cp38-cp38-manylinux2014_aarch64.whl", hash = "sha256:8f959b26f2634a091bb42241c3ed8d3cedb506e7c27b8dd5c7b9f745318ddbb6"},
|
||||
{file = "tornado-6.1-cp38-cp38-win32.whl", hash = "sha256:34ca2dac9e4d7afb0bed4677512e36a52f09caa6fded70b4e3e1c89dbd92c326"},
|
||||
{file = "tornado-6.1-cp38-cp38-win_amd64.whl", hash = "sha256:6196a5c39286cc37c024cd78834fb9345e464525d8991c21e908cc046d1cc02c"},
|
||||
{file = "tornado-6.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:f0ba29bafd8e7e22920567ce0d232c26d4d47c8b5cf4ed7b562b5db39fa199c5"},
|
||||
{file = "tornado-6.1-cp39-cp39-manylinux1_i686.whl", hash = "sha256:33892118b165401f291070100d6d09359ca74addda679b60390b09f8ef325ffe"},
|
||||
{file = "tornado-6.1-cp39-cp39-manylinux1_x86_64.whl", hash = "sha256:7da13da6f985aab7f6f28debab00c67ff9cbacd588e8477034c0652ac141feea"},
|
||||
{file = "tornado-6.1-cp39-cp39-manylinux2010_i686.whl", hash = "sha256:e0791ac58d91ac58f694d8d2957884df8e4e2f6687cdf367ef7eb7497f79eaa2"},
|
||||
{file = "tornado-6.1-cp39-cp39-manylinux2010_x86_64.whl", hash = "sha256:66324e4e1beede9ac79e60f88de548da58b1f8ab4b2f1354d8375774f997e6c0"},
|
||||
{file = "tornado-6.1-cp39-cp39-manylinux2014_aarch64.whl", hash = "sha256:a48900ecea1cbb71b8c71c620dee15b62f85f7c14189bdeee54966fbd9a0c5bd"},
|
||||
{file = "tornado-6.1-cp39-cp39-win32.whl", hash = "sha256:d3d20ea5782ba63ed13bc2b8c291a053c8d807a8fa927d941bd718468f7b950c"},
|
||||
{file = "tornado-6.1-cp39-cp39-win_amd64.whl", hash = "sha256:548430be2740e327b3fe0201abe471f314741efcb0067ec4f2d7dcfb4825f3e4"},
|
||||
{file = "tornado-6.1.tar.gz", hash = "sha256:33c6e81d7bd55b468d2e793517c909b139960b6c790a60b7991b9b6b76fb9791"},
|
||||
]
|
||||
typing-extensions = [
|
||||
{file = "typing_extensions-3.10.0.2-py2-none-any.whl", hash = "sha256:d8226d10bc02a29bcc81df19a26e56a9647f8b0a6d4a83924139f4a8b01f17b7"},
|
||||
{file = "typing_extensions-3.10.0.2-py3-none-any.whl", hash = "sha256:f1d25edafde516b146ecd0613dabcc61409817af4766fbbcfb8d1ad4ec441a34"},
|
||||
{file = "typing_extensions-3.10.0.2.tar.gz", hash = "sha256:49f75d16ff11f1cd258e1b988ccff82a3ca5570217d7ad8c5f48205dd99a677e"},
|
||||
]
|
||||
tzdata = [
|
||||
{file = "tzdata-2021.1-py2.py3-none-any.whl", hash = "sha256:9ad21eada54c97001e3e9858a674b3ee6bebe4a4fb2b58465930f2af0ba6c85d"},
|
||||
{file = "tzdata-2021.1.tar.gz", hash = "sha256:e19c7351f887522a1ac739d21041e592ddde6dd1b764fdefa8f7b2b3551d3d38"},
|
||||
]
|
||||
tzlocal = [
|
||||
{file = "tzlocal-3.0-py3-none-any.whl", hash = "sha256:c736f2540713deb5938d789ca7c3fc25391e9a20803f05b60ec64987cf086559"},
|
||||
{file = "tzlocal-3.0.tar.gz", hash = "sha256:f4e6e36db50499e0d92f79b67361041f048e2609d166e93456b50746dc4aef12"},
|
||||
]
|
||||
unidecode = [
|
||||
{file = "Unidecode-1.3.1-py3-none-any.whl", hash = "sha256:5f58926b9125b499f8ab6816828e737578fa3e31fa24d351a3ab7f4b7c064ab0"},
|
||||
{file = "Unidecode-1.3.1.tar.gz", hash = "sha256:6efac090bf8f29970afc90caf4daae87b172709b786cb1b4da2d0c0624431ecc"},
|
||||
]
|
||||
urllib3 = [
|
||||
{file = "urllib3-1.26.6-py2.py3-none-any.whl", hash = "sha256:39fb8672126159acb139a7718dd10806104dec1e2f0f6c88aab05d17df10c8d4"},
|
||||
{file = "urllib3-1.26.6.tar.gz", hash = "sha256:f57b4c16c62fa2760b7e3d97c35b255512fb6b59a259730f36ba32ce9f8e342f"},
|
||||
]
|
||||
youtube-dl = [
|
||||
{file = "youtube_dl-2021.6.6-py2.py3-none-any.whl", hash = "sha256:263e04d53fb8ba3dfbd246ad09b7d388e896c132a20cc770c26ee7684de050ac"},
|
||||
{file = "youtube_dl-2021.6.6.tar.gz", hash = "sha256:cb2d3ee002158ede783e97a82c95f3817594df54367ea6a77ce5ceea4772f0ab"},
|
||||
]
|
24
pyproject.toml
Normal file
24
pyproject.toml
Normal file
|
@ -0,0 +1,24 @@
|
|||
[tool.poetry]
|
||||
name = "delojza"
|
||||
version = "0.1.0"
|
||||
description = ""
|
||||
authors = ["Tomáš Mládek <t@mldk.cz>"]
|
||||
license = "MIT"
|
||||
|
||||
[tool.poetry.dependencies]
|
||||
python = "^3.8"
|
||||
python-telegram-bot = "^13.7"
|
||||
youtube_dl = "*"
|
||||
requests = "^2.26.0"
|
||||
filetype = "^1.0.7"
|
||||
mutagen = "^1.45.1"
|
||||
pyacoustid = "^1.2.2"
|
||||
PyTumblr = "^0.1.0"
|
||||
markovify = "^0.9.3"
|
||||
|
||||
[tool.poetry.dev-dependencies]
|
||||
black = {version = "^21.9b0", allow-prereleases = true}
|
||||
|
||||
[build-system]
|
||||
requires = ["poetry-core>=1.0.0"]
|
||||
build-backend = "poetry.core.masonry.api"
|
704
src/delojza.py
704
src/delojza.py
|
@ -1,704 +0,0 @@
|
|||
#!/usr/bin/env python3
|
||||
|
||||
import logging
|
||||
import os
|
||||
import pprint
|
||||
import re
|
||||
import shutil
|
||||
import subprocess
|
||||
import sys
|
||||
import tempfile
|
||||
from configparser import ConfigParser, NoSectionError
|
||||
from datetime import datetime, timedelta
|
||||
from glob import glob
|
||||
from operator import itemgetter
|
||||
from random import random
|
||||
from time import sleep
|
||||
|
||||
import acoustid
|
||||
import filetype
|
||||
import mutagen.id3
|
||||
import pytumblr
|
||||
import requests
|
||||
import telegram
|
||||
import youtube_dl
|
||||
from lib.db import DelojzaDB
|
||||
from lib.markov import MarkovBlabberer
|
||||
from lib.tagging import tag_file, get_tags
|
||||
from lib.util import mkdir_p, sanitize, ytdl_can
|
||||
from telegram.ext import Updater, CommandHandler, MessageHandler
|
||||
from youtube_dl import DownloadError
|
||||
from youtube_dl.version import __version__ as YTDL_VERSION
|
||||
|
||||
|
||||
class DelojzaBot:
|
||||
def __init__(self, tg_api_key, out_dir, redirects=None, tmp_dir=None, db_path=None, protected_password=None,
|
||||
acoustid_key=None, tumblr_name=None, tumblr_keys=None, markov=None):
|
||||
self._setup_logging(os.path.dirname(os.path.realpath(__file__)))
|
||||
|
||||
self.db = DelojzaDB(db_path or os.path.join(os.path.dirname(os.path.realpath(__file__)), "delojza.db"))
|
||||
|
||||
self.out_dir = os.path.abspath(out_dir)
|
||||
self.out_dir = self.out_dir[:-1] if self.out_dir[-1] == "/" else self.out_dir
|
||||
self.logger.debug('OUT_DIR: ' + out_dir)
|
||||
self.tmp_dir = tmp_dir if tmp_dir else tempfile.gettempdir()
|
||||
self.logger.debug('TMP_DIR: ' + tmp_dir)
|
||||
self.markov = markov
|
||||
|
||||
self.redirects = {}
|
||||
if redirects is not None:
|
||||
for hashtag, directory in redirects:
|
||||
hashtag = hashtag.upper()
|
||||
directory = directory[:-1] if directory[-1] == "/" else directory
|
||||
mkdir_p(directory)
|
||||
self.redirects[hashtag] = directory
|
||||
self.logger.debug(f"Will redirect hashtag {hashtag} to {directory}")
|
||||
|
||||
self.updater = Updater(tg_api_key)
|
||||
dp = self.updater.dispatcher
|
||||
|
||||
dp.add_handler(CommandHandler("start", self.tg_start))
|
||||
dp.add_error_handler(self.tg_error)
|
||||
dp.add_handler(CommandHandler("stats", self.tg_stats))
|
||||
dp.add_handler(CommandHandler("orphans", self.tg_orphan))
|
||||
dp.add_handler(CommandHandler("orphans_full", self.tg_orphan_full))
|
||||
dp.add_handler(CommandHandler("retag", self.tg_retag))
|
||||
dp.add_handler(CommandHandler("delete", self.tg_delete))
|
||||
dp.add_handler(CommandHandler("protect", self.tg_protect))
|
||||
dp.add_handler(CommandHandler("version", self.tg_version))
|
||||
dp.add_handler(CommandHandler("queue", self.tg_queue))
|
||||
dp.add_handler(MessageHandler(None, self.tg_handle))
|
||||
|
||||
self.acoustid_key = acoustid_key
|
||||
|
||||
if tumblr_name and tumblr_keys:
|
||||
self.tumblr_name = tumblr_name
|
||||
self.tumblr_client = pytumblr.TumblrRestClient(*tumblr_keys)
|
||||
else:
|
||||
self.tumblr_client = None
|
||||
|
||||
self.protected_password = protected_password
|
||||
self.last_downloaded = {}
|
||||
self.last_hashtags = {}
|
||||
|
||||
def _setup_logging(self, log_path):
|
||||
self.logger = logging.getLogger("delojza")
|
||||
self.logger.setLevel(logging.DEBUG)
|
||||
|
||||
ch = logging.StreamHandler()
|
||||
ch.setLevel(logging.INFO)
|
||||
|
||||
dfh = logging.FileHandler(log_path + "/delojza.log")
|
||||
dfh.setLevel(logging.DEBUG)
|
||||
|
||||
formatter = logging.Formatter('%(asctime)s - %(name)s [%(levelname)s] %(message)s')
|
||||
|
||||
ch.setFormatter(formatter)
|
||||
dfh.setFormatter(formatter)
|
||||
|
||||
self.logger.addHandler(ch)
|
||||
self.logger.addHandler(dfh)
|
||||
|
||||
def _log_msg(self, update):
|
||||
from_user = update.message.from_user
|
||||
self.logger.debug(f"Received from {from_user.username or (from_user.first_name + from_user.last_name)}"
|
||||
f" ({update.message.chat.id}): " + (update.message.text or "<NONE>"))
|
||||
|
||||
@staticmethod
|
||||
def datestr(date: datetime):
|
||||
return date.strftime("%Y-%m-%d@%H%M")
|
||||
|
||||
def _autotag_file(self, filepath, message, info=None):
|
||||
if info is None:
|
||||
info = {}
|
||||
|
||||
title = None
|
||||
artist = None
|
||||
source = None
|
||||
|
||||
best_acoustid_score = 0
|
||||
|
||||
if self.acoustid_key:
|
||||
try:
|
||||
self.logger.debug("Requesting AcoustID for {}".format(filepath))
|
||||
results = sorted(acoustid.match(self.acoustid_key, filepath), key=itemgetter(0), reverse=True)
|
||||
if len(results) > 0:
|
||||
score, rid, aid_title, aid_artist = results[0]
|
||||
if score > .4:
|
||||
title = aid_title
|
||||
artist = re.sub(r' *; +', ' & ', aid_artist)
|
||||
best_acoustid_score = score
|
||||
source = "AcoustID ({}%)".format(round(score * 100))
|
||||
except acoustid.NoBackendError:
|
||||
self.logger.warning("chromaprint library/tool not found")
|
||||
except acoustid.FingerprintGenerationError:
|
||||
self.logger.warning("fingerprint could not be calculated")
|
||||
except acoustid.WebServiceError as exc:
|
||||
self.logger.warning("web service request failed: {}".format(exc.message))
|
||||
|
||||
if best_acoustid_score < .8:
|
||||
if 'track' in info:
|
||||
title = info['track']
|
||||
if 'artist' in info:
|
||||
artist = info['artist']
|
||||
|
||||
if 'track' in info or 'artist' in info:
|
||||
source = "supplied metadata"
|
||||
|
||||
if title is None and artist is None and '-' in info.get("title", ""):
|
||||
split = info['title'].split("-")
|
||||
artist = split[0]
|
||||
title = split[1]
|
||||
source = "fallback (artist - title)"
|
||||
|
||||
if title is None and 'title' in info:
|
||||
title = info['title']
|
||||
source = "full title fallback"
|
||||
|
||||
if 'soundcloud' in info.get("extractor", "") and artist is None:
|
||||
artist = info['uploader']
|
||||
source = "soundcloud \"fallback\""
|
||||
|
||||
artist = artist.strip() if artist else None
|
||||
title = title.strip() if title else None
|
||||
|
||||
if title is None and artist is None:
|
||||
message.reply_text("Tried tagging, found nothing :(")
|
||||
return
|
||||
|
||||
message.reply_text("Tagging as \"{}\" by \"{}\"\nvia {}".format(title, artist, source))
|
||||
self.logger.info("Tagging {} w/ {} - {} [{}]...".format(filepath, title, artist, source))
|
||||
tag_file(filepath, artist, title)
|
||||
|
||||
# noinspection PyUnusedLocal
|
||||
def download_ytdl(self, urls, out_path, date, message, audio=False, filetitle=None):
|
||||
ytdl = {
|
||||
'noplaylist': True,
|
||||
'restrictfilenames': True,
|
||||
'outtmpl': os.path.join(self.tmp_dir, '{}__%(title)s__%(id)s.%(ext)s'.format(self.datestr(date)))
|
||||
}
|
||||
if audio:
|
||||
ytdl['format'] = 'bestaudio/best'
|
||||
ytdl['postprocessors'] = [{
|
||||
'key': 'FFmpegExtractAudio',
|
||||
'preferredcodec': 'mp3',
|
||||
'preferredquality': '256'
|
||||
}]
|
||||
ytdl['postprocessor_args'] = ['-ar', '44100']
|
||||
filenames = []
|
||||
with youtube_dl.YoutubeDL(ytdl) as ytdl:
|
||||
attempts = 0
|
||||
while True:
|
||||
try:
|
||||
ytdl.download(urls)
|
||||
break
|
||||
except DownloadError as exc:
|
||||
attempts += 1
|
||||
if '403' in str(exc) and attempts < 5:
|
||||
self.logger.warning("Received a 403!")
|
||||
sleep(1.357)
|
||||
if self.markov:
|
||||
message.reply_text(self.markov.make_sentence)
|
||||
else:
|
||||
raise exc
|
||||
for info in [ytdl.extract_info(url, download=False) for url in urls]:
|
||||
filename = ytdl.prepare_filename(info)
|
||||
globbeds = glob(os.path.splitext(filename)[0] + '.*')
|
||||
for globbed in globbeds:
|
||||
if globbed.endswith("mp3"):
|
||||
self._autotag_file(globbed, message, info=info)
|
||||
self.logger.info("Moving %s to %s..." % (globbed, out_path))
|
||||
dest = shutil.move(globbed, out_path)
|
||||
filenames.append(dest)
|
||||
return filenames
|
||||
|
||||
def download_raw(self, urls, out_path, date, message, audio=False, filetitle=None):
|
||||
filenames = []
|
||||
for url in urls:
|
||||
local_filename = os.path.join(out_path, "{}__{}".format(self.datestr(date),
|
||||
sanitize(filetitle or url.split('/')[-1])))
|
||||
final_filename = local_filename
|
||||
is_mp3 = local_filename.endswith("mp3")
|
||||
|
||||
r = requests.get(url, stream=True)
|
||||
with open(local_filename, 'wb') as f:
|
||||
for chunk in r.iter_content(chunk_size=1024):
|
||||
if chunk:
|
||||
f.write(chunk)
|
||||
|
||||
if not re.match(r'.*\..{3,5}$', os.path.split(local_filename)[-1]):
|
||||
kind = filetype.guess(local_filename)
|
||||
if kind is None:
|
||||
self.logger.error("File has no extension and could not be determined!")
|
||||
else:
|
||||
self.logger.info('Moving file without extension... %s?' % kind.extension)
|
||||
final_filename = shutil.move(local_filename, local_filename + '.' + kind.extension)
|
||||
is_mp3 = kind.extension == "mp3"
|
||||
|
||||
filenames.append(final_filename)
|
||||
|
||||
if audio and is_mp3:
|
||||
try:
|
||||
id3 = mutagen.id3.ID3(final_filename)
|
||||
untagged = 'TIT2' not in id3
|
||||
except mutagen.id3.ID3NoHeaderError:
|
||||
untagged = True
|
||||
if untagged:
|
||||
self._autotag_file(final_filename, message)
|
||||
|
||||
return filenames
|
||||
|
||||
@staticmethod
|
||||
def extract_hashtags(message):
|
||||
hashtags = list(map(message.parse_entity,
|
||||
list(filter(lambda e: e.type == 'hashtag', message.entities))))
|
||||
hashtags += list(map(message.parse_caption_entity,
|
||||
list(filter(lambda e: e.type == 'hashtag', message.caption_entities))))
|
||||
if len(hashtags) > 0:
|
||||
hashtags = [hashtag[1:].upper() for hashtag in hashtags]
|
||||
for i, hashtag in enumerate(hashtags):
|
||||
if "PRAS" in hashtag:
|
||||
hashtags[i] = "PRAS"
|
||||
return hashtags
|
||||
|
||||
def _get_hashtags(self, message):
|
||||
hashtags = self.extract_hashtags(message)
|
||||
if len(hashtags) == 0 and self.last_hashtags.get(message.chat.id) is not None:
|
||||
user, ts, last_hashtags = self.last_hashtags[message.chat.id]
|
||||
if user == message.from_user and ts > datetime.now() - timedelta(hours=1):
|
||||
hashtags = last_hashtags
|
||||
return hashtags
|
||||
|
||||
def handle_text(self, message, hashtags):
|
||||
if len(hashtags) == 0 or hashtags[0] not in ('TEXT', 'TXT'):
|
||||
return
|
||||
|
||||
info_line = sanitize("-".join(re.sub(r'#[\w]+', '', message.text).strip().split()[:7]))
|
||||
if len(info_line) > 64:
|
||||
info_line = info_line[:64]
|
||||
|
||||
filename = '{}__{}.txt'.format(self.datestr(message.date), info_line)
|
||||
out_dir = self.redirects.get(hashtags[0], self.out_dir)
|
||||
out_path = os.path.join(out_dir, *hashtags[1:] or ['TEXT'])
|
||||
file_path = os.path.join(out_path, filename)
|
||||
|
||||
mkdir_p(out_path)
|
||||
|
||||
with open(file_path, 'w') as out_file:
|
||||
out_file.write(message.text)
|
||||
|
||||
message.reply_text("Saved text to \"{}\"...".format(os.path.join(*hashtags[1:] or ['TEXT'], filename)))
|
||||
|
||||
# noinspection PyBroadException
|
||||
def handle(self, urls, message, hashtags, download_fn, filetitle=None):
|
||||
self.db.initialize()
|
||||
|
||||
try:
|
||||
if len(hashtags) == 0:
|
||||
self.logger.info("Ignoring %s due to no hashtag present..." % urls)
|
||||
return False
|
||||
|
||||
original_hashtags = hashtags
|
||||
if hashtags[0] in self.redirects:
|
||||
out_dir = self.redirects[hashtags[0]]
|
||||
hashtags = hashtags[1:]
|
||||
else:
|
||||
out_dir = self.out_dir
|
||||
|
||||
if any(hashtag in self.db.get_protected_tags() for hashtag in original_hashtags):
|
||||
if message.chat.id not in self.db.get_protected_chats():
|
||||
self.logger.info("Redirecting {} in chat {} due to protected hashtags: {}..."
|
||||
.format(urls, message.chat.title, hashtags))
|
||||
hashtags.insert(0, "PUBLIC")
|
||||
|
||||
for i in range(len(hashtags)):
|
||||
current_path = hashtags[:i + 1]
|
||||
if not os.path.isdir(os.path.join(out_dir, *current_path)):
|
||||
test_path = current_path
|
||||
test_path[-1] = "_" + test_path[-1]
|
||||
if os.path.isdir(os.path.join(out_dir, *test_path)):
|
||||
self.logger.debug(f"Rerouting {current_path[-1]} to _{test_path[-1]}")
|
||||
hashtags[i] = test_path[-1]
|
||||
|
||||
self.last_hashtags[message.chat.id] = None
|
||||
|
||||
self.logger.info("Downloading %s into '%s' (%s)" % (urls, "/".join(original_hashtags), out_dir))
|
||||
|
||||
out_path = os.path.join(out_dir, *hashtags)
|
||||
mkdir_p(out_path)
|
||||
|
||||
reply = 'Downloading to "{}"...'.format("/".join(original_hashtags))
|
||||
|
||||
audio = any([any([tag in hashtag for tag in ('AUDIO', 'RADIO')]) for hashtag in original_hashtags])
|
||||
if audio and download_fn != self.download_raw:
|
||||
reply += ' (And also guessing you want to extract the audio)'
|
||||
message.reply_text(reply)
|
||||
|
||||
filenames = download_fn(urls, out_path, message.date, message, audio=audio, filetitle=filetitle)
|
||||
|
||||
cmd_hashtag = original_hashtags[0]
|
||||
|
||||
tumblr_ids = []
|
||||
if cmd_hashtag in ('TUMBLR', 'TUMBLR_NOW') and self.tumblr_client:
|
||||
now = cmd_hashtag == 'TUMBLR_NOW'
|
||||
reply = '(btw, {})'.format("***FIRING TO TUMBLR RIGHT AWAY***" if now else "queueing to tumblr")
|
||||
message.reply_text(reply, parse_mode=telegram.ParseMode.MARKDOWN)
|
||||
for filename in filenames:
|
||||
if filename.endswith(".mp4"):
|
||||
try:
|
||||
output_filename = filename[:-len(".mp4")] + ".gif"
|
||||
subprocess.check_output(['ffmpeg', '-i', filename, output_filename])
|
||||
filename = output_filename
|
||||
except subprocess.CalledProcessError:
|
||||
message.reply_text("Conversion to gif failed, sorry! Check log...")
|
||||
continue
|
||||
response = self.tumblr_client.create_photo(self.tumblr_name, data=filename,
|
||||
state="published" if now else "queue")
|
||||
if 'id' in response:
|
||||
tumblr_ids.append(response['id'])
|
||||
else:
|
||||
self.logger.warning("Did not receive 'id' in tumblr response: \n" + pprint.pformat(response))
|
||||
message.reply_text('Something weird happened with the tumblrs, check it!')
|
||||
|
||||
self.last_downloaded[message.chat.id] = filenames, original_hashtags, tumblr_ids
|
||||
return True
|
||||
except:
|
||||
exc_type, exc_value, __ = sys.exc_info()
|
||||
if "Timed out" not in str(exc_value):
|
||||
message.reply_text("Something is FUCKED: [{}] {}".format(exc_type, exc_value))
|
||||
return False
|
||||
|
||||
def handle_tg_message(self, message, bot, hashtag):
|
||||
file, filetitle, tumblr = None, None, False
|
||||
if len(message.photo) > 0:
|
||||
photo = max(message.photo, key=lambda p: p.width)
|
||||
file = photo.file_id
|
||||
elif message.document is not None:
|
||||
filetitle = message.document.file_name
|
||||
file = message.document.file_id
|
||||
elif message.audio is not None:
|
||||
filetitle = message.audio.title
|
||||
file = message.audio.file_id
|
||||
elif message.video is not None:
|
||||
file = message.video.file_id
|
||||
elif message.video_note is not None:
|
||||
file = message.video_note.file_id
|
||||
elif message.voice is not None:
|
||||
file = message.voice.file_id
|
||||
|
||||
if file is not None:
|
||||
if self.markov and random() > .66:
|
||||
sentence = self.markov.make_sentence()
|
||||
if sentence:
|
||||
message.reply_text(sentence)
|
||||
url = bot.getFile(file).file_path
|
||||
return self.handle([url], message, hashtag, self.download_raw, filetitle=filetitle)
|
||||
else:
|
||||
return False
|
||||
|
||||
def handle_urls(self, message, hashtags):
|
||||
urls = list(map(lambda e: message.parse_entity(e),
|
||||
filter(lambda e: e.type == 'url', message.entities)))
|
||||
|
||||
if len(urls) > 0 and self.markov and random() > .66:
|
||||
sentence = self.markov.make_sentence()
|
||||
if sentence:
|
||||
message.reply_text(sentence)
|
||||
|
||||
ytdl_res = False
|
||||
ytdl_urls = [url for url in urls if ytdl_can(url)]
|
||||
if len(ytdl_urls) > 0:
|
||||
ytdl_res = self.handle(ytdl_urls, message, hashtags, self.download_ytdl)
|
||||
|
||||
raw_res = False
|
||||
normal_urls = [url for url in urls if not ytdl_can(url)]
|
||||
if len(normal_urls) > 0:
|
||||
file_urls = [url for url in normal_urls if
|
||||
"text" not in requests.head(url).headers.get("Content-Type", "text")]
|
||||
if len(file_urls) > 0:
|
||||
raw_res = self.handle(file_urls, message, hashtags, self.download_raw)
|
||||
|
||||
return ytdl_res or raw_res
|
||||
|
||||
def tg_handle(self, bot, update):
|
||||
self._log_msg(update)
|
||||
hashtags = self._get_hashtags(update.message)
|
||||
if hashtags:
|
||||
url_res = self.handle_urls(update.message, self._get_hashtags(update.message))
|
||||
if url_res:
|
||||
return
|
||||
|
||||
msg_res = self.handle_tg_message(update.message, bot, self._get_hashtags(update.message))
|
||||
if msg_res:
|
||||
return
|
||||
|
||||
hashtags = self.extract_hashtags(update.message)
|
||||
if len(hashtags) > 0:
|
||||
self.handle_text(update.message.reply_to_message or update.message, hashtags)
|
||||
|
||||
if update.message.reply_to_message:
|
||||
self.handle_tg_message(update.message.reply_to_message, bot, hashtags)
|
||||
self.handle_urls(update.message.reply_to_message, hashtags)
|
||||
else:
|
||||
self.last_hashtags[update.message.chat.id] = update.message.from_user, datetime.now(), hashtags
|
||||
else:
|
||||
if self.markov and update.message.text:
|
||||
self.markov.add_to_corpus(update.message.text)
|
||||
|
||||
def _get_tag_dirs(self):
|
||||
return list(filter(lambda x: x.upper() == x,
|
||||
filter(lambda directory: os.path.isdir(os.path.join(self.out_dir, directory)),
|
||||
os.listdir(self.out_dir)))) + list(self.redirects.keys())
|
||||
|
||||
def tg_stats(self, _, update):
|
||||
self._log_msg(update)
|
||||
self.db.initialize()
|
||||
if update.message.chat.id not in self.db.get_protected_chats():
|
||||
update.message.reply_text((self.markov.make_sentence() + "!") if self.markov and random() > .7 else "nope.")
|
||||
return
|
||||
tag_dirs = self._get_tag_dirs()
|
||||
reply = "Total number of tags: {}\n\n".format(len(tag_dirs))
|
||||
counts = [(directory, os.listdir(os.path.join(self.out_dir, directory))) for directory in
|
||||
tag_dirs] # TODO REDIRECTS
|
||||
counts.sort(key=itemgetter(0))
|
||||
counts.sort(key=lambda x: len(x[1]), reverse=True)
|
||||
for directory, files in counts:
|
||||
if len(files) == 1:
|
||||
break
|
||||
abs_paths = [os.path.join(self.out_dir, directory, file) for file in files] # TODO REDIRECTS
|
||||
abs_files = list(filter(os.path.isfile, abs_paths))
|
||||
# mimes = [magic.from_file(path, mime=True).split("/")[0] for path in abs_files]
|
||||
# mime_counts = [(mime, mimes.count(mime)) for mime in set(mimes)]
|
||||
exts = [ext[1:] for ext in [os.path.splitext(path)[1] for path in abs_files] if len(ext) > 0]
|
||||
ext_counts = [(ext, exts.count(ext)) for ext in set(exts)]
|
||||
dir_cnt = len(abs_paths) - len(abs_files)
|
||||
type_counts = ext_counts + ([("directorie", dir_cnt)] if dir_cnt > 0 else [])
|
||||
details = ", ".join(["{} {}s".format(cnt, mime) for mime, cnt in
|
||||
sorted(type_counts, key=itemgetter(1), reverse=True)])
|
||||
if len(type_counts) == 1:
|
||||
reply += "<b>{}:</b> {}\n".format(directory, details)
|
||||
else:
|
||||
reply += "<b>{}:</b> {} files ({})\n".format(directory, len(files), details)
|
||||
orphans = list(filter(lambda cnt: len(cnt[1]) <= 1, counts))
|
||||
if len(orphans) > 0:
|
||||
reply += "\nFollowing tags are orphans: " + ", ".join(map(itemgetter(0), orphans))
|
||||
update.message.reply_text(reply, parse_mode=telegram.ParseMode.HTML)
|
||||
|
||||
def _get_orphan_tags(self):
|
||||
result = []
|
||||
for directory in self._get_tag_dirs():
|
||||
files = os.listdir(os.path.join(self.out_dir, directory))
|
||||
if len(files) == 1:
|
||||
result.append((directory, files[0]))
|
||||
if len(files) == 0:
|
||||
result.append((directory, "NO FILE AT ALL..."))
|
||||
return sorted(result, key=itemgetter(0))
|
||||
|
||||
def tg_orphan(self, _, update):
|
||||
self._log_msg(update)
|
||||
self.db.initialize()
|
||||
if update.message.chat.id not in self.db.get_protected_chats():
|
||||
update.message.reply_text((self.markov.make_sentence() + "!") if self.markov and random() > .7 else "nope.")
|
||||
return
|
||||
orphans = self._get_orphan_tags()
|
||||
if len(orphans) == 0:
|
||||
update.message.reply_text("Good job, no orphan tags!")
|
||||
else:
|
||||
update.message.reply_text("The following tags only contain a single file:\n" +
|
||||
", ".join(map(itemgetter(0), orphans)))
|
||||
|
||||
def tg_orphan_full(self, _, update):
|
||||
self._log_msg(update)
|
||||
self.db.initialize()
|
||||
if update.message.chat.id not in self.db.get_protected_chats():
|
||||
update.message.reply_text((self.markov.make_sentence() + "!") if self.markov and random() > .7 else "nope.")
|
||||
return
|
||||
orphans = self._get_orphan_tags()
|
||||
if len(orphans) == 0:
|
||||
update.message.reply_text("Good job, no orphan tags!")
|
||||
else:
|
||||
tmp_reply = "The following tags only contain a single file:\n"
|
||||
for directory, file in orphans:
|
||||
line = "{}: {}\n".format(directory, file)
|
||||
if len(tmp_reply + line) > 4096:
|
||||
update.message.reply_text(tmp_reply)
|
||||
tmp_reply = ""
|
||||
tmp_reply += line
|
||||
if len(tmp_reply) > 0:
|
||||
update.message.reply_text(tmp_reply)
|
||||
|
||||
def tg_retag(self, _, update):
|
||||
self._log_msg(update)
|
||||
if self.last_downloaded.get(update.message.chat.id) is not None:
|
||||
files, hashtags, tumblr_ids = self.last_downloaded[update.message.chat.id]
|
||||
out_dir = self.redirects.get(hashtags[0], self.out_dir)
|
||||
mp3s = [filename for filename in files if filename.endswith("mp3")]
|
||||
if len(mp3s) > 0:
|
||||
arg_raw = re.sub(r'^/[@\w]+ ?', '', update.message.text).strip()
|
||||
artist, title = None, None
|
||||
|
||||
reverse = len(arg_raw) == 0
|
||||
if not reverse:
|
||||
tagline = arg_raw.split(" - ")
|
||||
if len(tagline) == 1:
|
||||
title = tagline[0].strip()
|
||||
else:
|
||||
artist = tagline[0].strip()
|
||||
title = tagline[1].strip()
|
||||
|
||||
for mp3 in mp3s:
|
||||
if reverse:
|
||||
orig_artist, orig_title = get_tags(mp3)
|
||||
title, artist = orig_artist, orig_title
|
||||
|
||||
tag_file(mp3, artist, title)
|
||||
update.message.reply_text("Tagging \"{}\" as \"{}\" by \"{}\"!"
|
||||
.format(mp3[len(out_dir) + 1:], title, artist))
|
||||
else:
|
||||
update.message.reply_text((self.markov.make_sentence() if self.markov and random() > .7 else "") + "???")
|
||||
|
||||
def tg_delete(self, _, update):
|
||||
self._log_msg(update)
|
||||
if self.last_downloaded.get(update.message.chat.id) is not None:
|
||||
files, hashtags, tumblr_ids = self.last_downloaded[update.message.chat.id]
|
||||
out_dir = self.redirects.get(hashtags[0], self.out_dir)
|
||||
for file in files:
|
||||
update.message.reply_text("Removing \"{}\"!".format(file[len(out_dir) + 1:]))
|
||||
os.remove(file)
|
||||
parent_dir = os.path.dirname(file)
|
||||
while True:
|
||||
if len(os.listdir(parent_dir)) == 0:
|
||||
update.message.reply_text("Removing directory \"{}\" as it's empty..."
|
||||
.format(parent_dir[len(out_dir) + 1:]))
|
||||
os.rmdir(parent_dir)
|
||||
if parent_dir == out_dir:
|
||||
break
|
||||
parent_dir = os.path.dirname(parent_dir)
|
||||
if len(tumblr_ids) > 0:
|
||||
plural = "s (all {} of them)".format(len(tumblr_ids)) if len(tumblr_ids) > 1 else ""
|
||||
update.message.reply_text("Also deleting tumblr post{}!".format(plural))
|
||||
for tumblr_id in tumblr_ids:
|
||||
if self.tumblr_client:
|
||||
self.tumblr_client.delete_post(self.tumblr_name, tumblr_id)
|
||||
self.last_downloaded[update.message.chat.id] = None
|
||||
return
|
||||
update.message.reply_text("Nothing to remove!")
|
||||
|
||||
def tg_protect(self, _, update):
|
||||
self._log_msg(update)
|
||||
self.db.initialize()
|
||||
|
||||
msg_split = update.message.text.split(" ")
|
||||
if len(msg_split) != 3:
|
||||
update.message.reply_text((self.markov.make_sentence() if self.markov and random() > .7 else "") + "???")
|
||||
return
|
||||
|
||||
chat_in_db = self.db.get_chat(update.message.chat.id)
|
||||
|
||||
cmd = msg_split[1]
|
||||
if cmd == 'tag':
|
||||
if chat_in_db and chat_in_db[1]:
|
||||
tag = msg_split[2].upper()
|
||||
tag_in_db = self.db.get_tag(tag)
|
||||
if tag_in_db:
|
||||
_, _, protected = tag_in_db
|
||||
end_protected = not protected
|
||||
else:
|
||||
end_protected = True
|
||||
|
||||
self.db.set_tag_protected(tag, end_protected)
|
||||
update.message.reply_text(f"got it, will {'NOT ' if not end_protected else ''}protect tag {tag}!")
|
||||
else:
|
||||
update.message.reply_text((self.markov.make_sentence() if self.markov and random() > .7 else "hublubl"))
|
||||
elif cmd == 'chat':
|
||||
password = msg_split[2]
|
||||
if password == self.protected_password:
|
||||
if chat_in_db:
|
||||
_, protected = chat_in_db
|
||||
end_protected = not protected
|
||||
else:
|
||||
end_protected = True
|
||||
|
||||
self.db.set_chat_protected(update.message.chat.id, end_protected)
|
||||
update.message.reply_text(f"got it, will {'NOT ' if not end_protected else ''}protect this chat!")
|
||||
else:
|
||||
update.message.reply_text((self.markov.make_sentence() if self.markov and random() > .7 else "hublubl"))
|
||||
else:
|
||||
update.message.reply_text((self.markov.make_sentence() if self.markov and random() > .7 else "") + "???")
|
||||
|
||||
def tg_queue(self, _, update):
|
||||
if self.tumblr_client:
|
||||
blog_info = self.tumblr_client.blog_info(self.tumblr_name)
|
||||
update.message.reply_text("Currently queued tumblr posts: " + str(blog_info['blog'].get('queue', "???")))
|
||||
else:
|
||||
update.message.reply_text((self.markov.make_sentence() if self.markov and random() > .7 else "") + "???")
|
||||
|
||||
# noinspection PyMethodMayBeStatic
|
||||
def tg_version(self, _, update):
|
||||
self._log_msg(update)
|
||||
delojza_date = datetime.fromtimestamp(os.path.getmtime(os.path.realpath(__file__))) \
|
||||
.strftime('%Y/%m/%d - %H:%M:%S')
|
||||
update.message.reply_text("delojza modified date: {}\nyoutube-dl version: {}"
|
||||
.format(delojza_date, YTDL_VERSION))
|
||||
|
||||
def tg_start(self, _, update):
|
||||
self._log_msg(update)
|
||||
update.message.reply_text(self.markov.make_sentence() if self.markov else "HELLO")
|
||||
|
||||
def tg_error(self, bot, update, error):
|
||||
self.logger.error(error)
|
||||
if "Timed out" in str(error):
|
||||
if update is not None:
|
||||
default = "Mmmm, I like it..."
|
||||
update.message.reply_text((self.markov.make_sentence(tries=100) if self.markov else default) or default)
|
||||
self.tg_handle(bot, update)
|
||||
else:
|
||||
if update is not None:
|
||||
update.message.reply_text("Something is fucked: %s" % error)
|
||||
|
||||
def run_idle(self):
|
||||
self.updater.start_polling()
|
||||
self.logger.info("Started Telegram bot...")
|
||||
self.updater.idle()
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
logging.basicConfig(level=logging.INFO, format='%(asctime)s - %(name)s - %(levelname)s - %(message)s')
|
||||
|
||||
_DIR_ = os.path.dirname(os.path.realpath(__file__))
|
||||
CONFIG_PATHS = ['/etc/delojza/delojza.ini',
|
||||
os.path.join(os.getenv("HOME") or "", ".config/delojza/delojza.ini"),
|
||||
os.path.join(_DIR_, "delojza.ini")]
|
||||
|
||||
config = ConfigParser()
|
||||
try:
|
||||
CONF_FILE = next(conf_path for conf_path in CONFIG_PATHS if os.path.isfile(conf_path))
|
||||
config.read(CONF_FILE)
|
||||
except StopIteration:
|
||||
logging.error("No config file found, stopping.")
|
||||
sys.exit(-1)
|
||||
|
||||
try:
|
||||
markov = MarkovBlabberer("initial.txt")
|
||||
except FileNotFoundError:
|
||||
logging.warning("Didn't find `initial.txt`, continuing without markov blabbering!")
|
||||
markov = None
|
||||
|
||||
try:
|
||||
redirects = config.items('redirects')
|
||||
except NoSectionError:
|
||||
redirects = {}
|
||||
|
||||
delojza = DelojzaBot(config.get('delojza', 'tg_api_key'),
|
||||
config.get('delojza', 'OUT_DIR', fallback=os.path.join(_DIR_, "out")),
|
||||
tmp_dir=config.get('delojza', 'tmp_dir', fallback=tempfile.gettempdir()),
|
||||
redirects=redirects,
|
||||
protected_password=config.get('delojza', 'protected_password', fallback=None),
|
||||
acoustid_key=config.get('delojza', 'acoustid_api_key', fallback=None),
|
||||
tumblr_name=config.get('tumblr', 'blog_name', fallback=None),
|
||||
tumblr_keys=(config.get('tumblr', 'consumer_key', fallback=None),
|
||||
config.get('tumblr', 'consumer_secret', fallback=None),
|
||||
config.get('tumblr', 'oauth_key', fallback=None),
|
||||
config.get('tumblr', 'oauth_secret', fallback=None)),
|
||||
markov=markov)
|
||||
delojza.run_idle()
|
|
@ -1,42 +0,0 @@
|
|||
import sqlite3
|
||||
from typing import List
|
||||
|
||||
|
||||
class DelojzaDB:
|
||||
def __init__(self, db_path):
|
||||
self.db_path = db_path
|
||||
self.db = None
|
||||
|
||||
def initialize(self) -> None:
|
||||
if self.db is None:
|
||||
self.db = sqlite3.connect(self.db_path)
|
||||
|
||||
def get_protected_tags(self) -> List[str]:
|
||||
results = self.db.execute("SELECT tag FROM tags WHERE protected == 1")
|
||||
return [res[0] for res in results.fetchall()]
|
||||
|
||||
def get_protected_chats(self) -> List[str]:
|
||||
results = self.db.execute("SELECT id FROM chats WHERE protected == 1")
|
||||
return [res[0] for res in results.fetchall()]
|
||||
|
||||
def get_chat(self, id):
|
||||
return self.db.execute("SELECT id, protected FROM chats WHERE id == ?", (id,)).fetchone()
|
||||
|
||||
def set_chat_protected(self, id, protected):
|
||||
chat_in_db = self.get_chat(id)
|
||||
if chat_in_db:
|
||||
self.db.execute("UPDATE chats SET protected = ? WHERE id = ?", (protected, id))
|
||||
else:
|
||||
self.db.execute("INSERT INTO chats (id, protected) VALUES (?, ?)", (id, protected))
|
||||
self.db.commit()
|
||||
|
||||
def get_tag(self, tag):
|
||||
return self.db.execute("SELECT id, tag, protected FROM tags WHERE tag == ?", (tag,)).fetchone()
|
||||
|
||||
def set_tag_protected(self, tag, protected):
|
||||
tag_in_db = self.get_tag(tag)
|
||||
if tag_in_db:
|
||||
self.db.execute("UPDATE tags SET protected = ? WHERE tag = ?", (protected, tag))
|
||||
else:
|
||||
self.db.execute("INSERT INTO tags (tag, protected) VALUES (?, ?)", (tag, protected))
|
||||
self.db.commit()
|
|
@ -1,25 +0,0 @@
|
|||
import logging
|
||||
|
||||
import markovify
|
||||
from unidecode import unidecode
|
||||
|
||||
|
||||
class MarkovBlabberer:
|
||||
def __init__(self, filepath):
|
||||
self.logger = logging.getLogger('markov')
|
||||
self.filepath = filepath
|
||||
|
||||
with open(filepath) as f:
|
||||
text = f.read()
|
||||
self.markov = markovify.NewlineText(unidecode(text.lower()))
|
||||
self.logger.info("Sentence of the day: " + self.make_sentence())
|
||||
|
||||
def make_sentence(self, tries=100):
|
||||
return self.markov.make_sentence(tries=tries) or "???"
|
||||
|
||||
def add_to_corpus(self, text):
|
||||
text = text.lower()
|
||||
new_sentence = markovify.NewlineText(text)
|
||||
self.markov = markovify.combine([self.markov, new_sentence])
|
||||
with open(self.filepath, 'a') as f:
|
||||
f.write(text + '\n')
|
|
@ -1,25 +0,0 @@
|
|||
import mutagen.id3
|
||||
from mutagen.easyid3 import EasyID3
|
||||
|
||||
|
||||
def get_tags(filepath):
|
||||
try:
|
||||
audio = EasyID3(filepath)
|
||||
return audio["artist"][0] if audio["artist"] else None, audio["title"][0] if audio["title"] else None
|
||||
except mutagen.id3.ID3NoHeaderError:
|
||||
return None, None
|
||||
|
||||
|
||||
def tag_file(filepath, artist, title):
|
||||
try:
|
||||
id3 = mutagen.id3.ID3(filepath)
|
||||
except mutagen.id3.ID3NoHeaderError:
|
||||
mutafile = mutagen.File(filepath)
|
||||
mutafile.add_tags()
|
||||
mutafile.save()
|
||||
id3 = mutagen.id3.ID3(filepath)
|
||||
id3.add(mutagen.id3.TIT2(encoding=3, text=title))
|
||||
if artist:
|
||||
id3.add(mutagen.id3.TOPE(encoding=3, text=artist))
|
||||
id3.add(mutagen.id3.TPE1(encoding=3, text=artist))
|
||||
id3.save()
|
|
@ -1,43 +0,0 @@
|
|||
import errno
|
||||
import os
|
||||
import re
|
||||
import subprocess
|
||||
import unicodedata
|
||||
|
||||
import youtube_dl
|
||||
|
||||
|
||||
def ytdl_can(url: str):
|
||||
ies = youtube_dl.extractor.gen_extractors()
|
||||
for ie in ies:
|
||||
if ie.suitable(url) and ie.IE_NAME != 'generic' \
|
||||
and '/channel/' not in url:
|
||||
# Site has dedicated extractor
|
||||
return True
|
||||
return False
|
||||
|
||||
|
||||
def mkdir_p(path: str):
|
||||
try:
|
||||
os.makedirs(path)
|
||||
except OSError as exc:
|
||||
if exc.errno == errno.EEXIST and os.path.isdir(path):
|
||||
pass
|
||||
else:
|
||||
raise
|
||||
|
||||
|
||||
def _get_percent_filled(directory: str):
|
||||
output = subprocess.check_output(["df", directory])
|
||||
percents_re = re.search(r"[0-9]+%", output.decode('utf-8'))
|
||||
if not percents_re:
|
||||
raise RuntimeError
|
||||
return int(percents_re.group(0)[:-1])
|
||||
|
||||
|
||||
# https://github.com/django/django/blob/master/django/utils/text.py#L393
|
||||
def sanitize(filepath: str):
|
||||
if filepath is None:
|
||||
return None
|
||||
filepath = unicodedata.normalize('NFKD', filepath).encode('ascii', 'ignore').decode('ascii')
|
||||
return re.sub(r'[^\w.()\[\]{}#-]', '_', filepath)
|
393
src/poetry.lock
generated
393
src/poetry.lock
generated
|
@ -1,393 +0,0 @@
|
|||
[[package]]
|
||||
category = "main"
|
||||
description = "multi-library, cross-platform audio decoding"
|
||||
name = "audioread"
|
||||
optional = false
|
||||
python-versions = "*"
|
||||
version = "2.1.8"
|
||||
|
||||
[[package]]
|
||||
category = "main"
|
||||
description = "Python package for providing Mozilla's CA Bundle."
|
||||
name = "certifi"
|
||||
optional = false
|
||||
python-versions = "*"
|
||||
version = "2019.11.28"
|
||||
|
||||
[[package]]
|
||||
category = "main"
|
||||
description = "Foreign Function Interface for Python calling C code."
|
||||
name = "cffi"
|
||||
optional = false
|
||||
python-versions = "*"
|
||||
version = "1.14.0"
|
||||
|
||||
[package.dependencies]
|
||||
pycparser = "*"
|
||||
|
||||
[[package]]
|
||||
category = "main"
|
||||
description = "Universal encoding detector for Python 2 and 3"
|
||||
name = "chardet"
|
||||
optional = false
|
||||
python-versions = "*"
|
||||
version = "3.0.4"
|
||||
|
||||
[[package]]
|
||||
category = "main"
|
||||
description = "cryptography is a package which provides cryptographic recipes and primitives to Python developers."
|
||||
name = "cryptography"
|
||||
optional = false
|
||||
python-versions = ">=2.7,!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*"
|
||||
version = "2.8"
|
||||
|
||||
[package.dependencies]
|
||||
cffi = ">=1.8,<1.11.3 || >1.11.3"
|
||||
six = ">=1.4.1"
|
||||
|
||||
[package.extras]
|
||||
docs = ["sphinx (>=1.6.5,<1.8.0 || >1.8.0)", "sphinx-rtd-theme"]
|
||||
docstest = ["doc8", "pyenchant (>=1.6.11)", "twine (>=1.12.0)", "sphinxcontrib-spelling (>=4.0.1)"]
|
||||
idna = ["idna (>=2.1)"]
|
||||
pep8test = ["flake8", "flake8-import-order", "pep8-naming"]
|
||||
test = ["pytest (>=3.6.0,<3.9.0 || >3.9.0,<3.9.1 || >3.9.1,<3.9.2 || >3.9.2)", "pretend", "iso8601", "pytz", "hypothesis (>=1.11.4,<3.79.2 || >3.79.2)"]
|
||||
|
||||
[[package]]
|
||||
category = "main"
|
||||
description = "Decorators for Humans"
|
||||
name = "decorator"
|
||||
optional = false
|
||||
python-versions = ">=2.6, !=3.0.*, !=3.1.*"
|
||||
version = "4.4.2"
|
||||
|
||||
[[package]]
|
||||
category = "main"
|
||||
description = "Infer file type and MIME type of any file/buffer. No external dependencies."
|
||||
name = "filetype"
|
||||
optional = false
|
||||
python-versions = "*"
|
||||
version = "1.0.6"
|
||||
|
||||
[[package]]
|
||||
category = "main"
|
||||
description = "Clean single-source support for Python 3 and 2"
|
||||
name = "future"
|
||||
optional = false
|
||||
python-versions = ">=2.6, !=3.0.*, !=3.1.*, !=3.2.*"
|
||||
version = "0.18.2"
|
||||
|
||||
[[package]]
|
||||
category = "main"
|
||||
description = "Internationalized Domain Names in Applications (IDNA)"
|
||||
name = "idna"
|
||||
optional = false
|
||||
python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*"
|
||||
version = "2.9"
|
||||
|
||||
[[package]]
|
||||
category = "main"
|
||||
description = "A simple, extensible Markov chain generator. Uses include generating random semi-plausible sentences based on an existing text."
|
||||
name = "markovify"
|
||||
optional = false
|
||||
python-versions = "*"
|
||||
version = "0.8.0"
|
||||
|
||||
[package.dependencies]
|
||||
unidecode = "*"
|
||||
|
||||
[[package]]
|
||||
category = "main"
|
||||
description = "read and write audio tags for many formats"
|
||||
name = "mutagen"
|
||||
optional = false
|
||||
python-versions = ">=3.5, <4"
|
||||
version = "1.44.0"
|
||||
|
||||
[[package]]
|
||||
category = "main"
|
||||
description = "A generic, spec-compliant, thorough implementation of the OAuth request-signing logic"
|
||||
name = "oauthlib"
|
||||
optional = false
|
||||
python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*"
|
||||
version = "3.1.0"
|
||||
|
||||
[package.extras]
|
||||
rsa = ["cryptography"]
|
||||
signals = ["blinker"]
|
||||
signedtoken = ["cryptography", "pyjwt (>=1.0.0)"]
|
||||
|
||||
[[package]]
|
||||
category = "main"
|
||||
description = "bindings for Chromaprint acoustic fingerprinting and the Acoustid API"
|
||||
name = "pyacoustid"
|
||||
optional = false
|
||||
python-versions = "*"
|
||||
version = "1.1.7"
|
||||
|
||||
[package.dependencies]
|
||||
audioread = "*"
|
||||
requests = "*"
|
||||
|
||||
[[package]]
|
||||
category = "main"
|
||||
description = "C parser in Python"
|
||||
name = "pycparser"
|
||||
optional = false
|
||||
python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*"
|
||||
version = "2.20"
|
||||
|
||||
[[package]]
|
||||
category = "main"
|
||||
description = "We have made you a wrapper you can't refuse"
|
||||
name = "python-telegram-bot"
|
||||
optional = false
|
||||
python-versions = "*"
|
||||
version = "12.4.2"
|
||||
|
||||
[package.dependencies]
|
||||
certifi = "*"
|
||||
cryptography = "*"
|
||||
decorator = ">=4.4.0"
|
||||
future = ">=0.16.0"
|
||||
tornado = ">=5.1"
|
||||
|
||||
[package.extras]
|
||||
json = ["ujson"]
|
||||
socks = ["pysocks"]
|
||||
|
||||
[[package]]
|
||||
category = "main"
|
||||
description = "A Python API v2 wrapper for Tumblr"
|
||||
name = "pytumblr"
|
||||
optional = false
|
||||
python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*"
|
||||
version = "0.1.0"
|
||||
|
||||
[package.dependencies]
|
||||
future = "*"
|
||||
requests-oauthlib = "*"
|
||||
|
||||
[[package]]
|
||||
category = "main"
|
||||
description = "Python HTTP for Humans."
|
||||
name = "requests"
|
||||
optional = false
|
||||
python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*"
|
||||
version = "2.23.0"
|
||||
|
||||
[package.dependencies]
|
||||
certifi = ">=2017.4.17"
|
||||
chardet = ">=3.0.2,<4"
|
||||
idna = ">=2.5,<3"
|
||||
urllib3 = ">=1.21.1,<1.25.0 || >1.25.0,<1.25.1 || >1.25.1,<1.26"
|
||||
|
||||
[package.extras]
|
||||
security = ["pyOpenSSL (>=0.14)", "cryptography (>=1.3.4)"]
|
||||
socks = ["PySocks (>=1.5.6,<1.5.7 || >1.5.7)", "win-inet-pton"]
|
||||
|
||||
[[package]]
|
||||
category = "main"
|
||||
description = "OAuthlib authentication support for Requests."
|
||||
name = "requests-oauthlib"
|
||||
optional = false
|
||||
python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*"
|
||||
version = "1.3.0"
|
||||
|
||||
[package.dependencies]
|
||||
oauthlib = ">=3.0.0"
|
||||
requests = ">=2.0.0"
|
||||
|
||||
[package.extras]
|
||||
rsa = ["oauthlib (>=3.0.0)"]
|
||||
|
||||
[[package]]
|
||||
category = "main"
|
||||
description = "Python 2 and 3 compatibility utilities"
|
||||
name = "six"
|
||||
optional = false
|
||||
python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*"
|
||||
version = "1.14.0"
|
||||
|
||||
[[package]]
|
||||
category = "main"
|
||||
description = "Tornado is a Python web framework and asynchronous networking library, originally developed at FriendFeed."
|
||||
name = "tornado"
|
||||
optional = false
|
||||
python-versions = ">= 3.5"
|
||||
version = "6.0.4"
|
||||
|
||||
[[package]]
|
||||
category = "main"
|
||||
description = "ASCII transliterations of Unicode text"
|
||||
name = "unidecode"
|
||||
optional = false
|
||||
python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*"
|
||||
version = "1.1.1"
|
||||
|
||||
[[package]]
|
||||
category = "main"
|
||||
description = "HTTP library with thread-safe connection pooling, file post, and more."
|
||||
name = "urllib3"
|
||||
optional = false
|
||||
python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*, <4"
|
||||
version = "1.25.8"
|
||||
|
||||
[package.extras]
|
||||
brotli = ["brotlipy (>=0.6.0)"]
|
||||
secure = ["pyOpenSSL (>=0.14)", "cryptography (>=1.3.4)", "idna (>=2.0.0)", "certifi", "ipaddress"]
|
||||
socks = ["PySocks (>=1.5.6,<1.5.7 || >1.5.7,<2.0)"]
|
||||
|
||||
[[package]]
|
||||
category = "main"
|
||||
description = "YouTube video downloader"
|
||||
name = "youtube-dl"
|
||||
optional = false
|
||||
python-versions = "*"
|
||||
version = "2020.3.24"
|
||||
|
||||
[metadata]
|
||||
content-hash = "dd08867932866aa57fdeebf8d02ff9c14739cd099e039ca310222679905ab4e4"
|
||||
python-versions = "^3.8"
|
||||
|
||||
[metadata.files]
|
||||
audioread = [
|
||||
{file = "audioread-2.1.8.tar.gz", hash = "sha256:073904fabc842881e07bd3e4a5776623535562f70b1655b635d22886168dd168"},
|
||||
]
|
||||
certifi = [
|
||||
{file = "certifi-2019.11.28-py2.py3-none-any.whl", hash = "sha256:017c25db2a153ce562900032d5bc68e9f191e44e9a0f762f373977de9df1fbb3"},
|
||||
{file = "certifi-2019.11.28.tar.gz", hash = "sha256:25b64c7da4cd7479594d035c08c2d809eb4aab3a26e5a990ea98cc450c320f1f"},
|
||||
]
|
||||
cffi = [
|
||||
{file = "cffi-1.14.0-cp27-cp27m-macosx_10_9_x86_64.whl", hash = "sha256:1cae98a7054b5c9391eb3249b86e0e99ab1e02bb0cc0575da191aedadbdf4384"},
|
||||
{file = "cffi-1.14.0-cp27-cp27m-manylinux1_i686.whl", hash = "sha256:cf16e3cf6c0a5fdd9bc10c21687e19d29ad1fe863372b5543deaec1039581a30"},
|
||||
{file = "cffi-1.14.0-cp27-cp27m-manylinux1_x86_64.whl", hash = "sha256:f2b0fa0c01d8a0c7483afd9f31d7ecf2d71760ca24499c8697aeb5ca37dc090c"},
|
||||
{file = "cffi-1.14.0-cp27-cp27m-win32.whl", hash = "sha256:99f748a7e71ff382613b4e1acc0ac83bf7ad167fb3802e35e90d9763daba4d78"},
|
||||
{file = "cffi-1.14.0-cp27-cp27m-win_amd64.whl", hash = "sha256:c420917b188a5582a56d8b93bdd8e0f6eca08c84ff623a4c16e809152cd35793"},
|
||||
{file = "cffi-1.14.0-cp27-cp27mu-manylinux1_i686.whl", hash = "sha256:399aed636c7d3749bbed55bc907c3288cb43c65c4389964ad5ff849b6370603e"},
|
||||
{file = "cffi-1.14.0-cp27-cp27mu-manylinux1_x86_64.whl", hash = "sha256:cab50b8c2250b46fe738c77dbd25ce017d5e6fb35d3407606e7a4180656a5a6a"},
|
||||
{file = "cffi-1.14.0-cp35-cp35m-macosx_10_9_x86_64.whl", hash = "sha256:001bf3242a1bb04d985d63e138230802c6c8d4db3668fb545fb5005ddf5bb5ff"},
|
||||
{file = "cffi-1.14.0-cp35-cp35m-manylinux1_i686.whl", hash = "sha256:e56c744aa6ff427a607763346e4170629caf7e48ead6921745986db3692f987f"},
|
||||
{file = "cffi-1.14.0-cp35-cp35m-manylinux1_x86_64.whl", hash = "sha256:b8c78301cefcf5fd914aad35d3c04c2b21ce8629b5e4f4e45ae6812e461910fa"},
|
||||
{file = "cffi-1.14.0-cp35-cp35m-win32.whl", hash = "sha256:8c0ffc886aea5df6a1762d0019e9cb05f825d0eec1f520c51be9d198701daee5"},
|
||||
{file = "cffi-1.14.0-cp35-cp35m-win_amd64.whl", hash = "sha256:8a6c688fefb4e1cd56feb6c511984a6c4f7ec7d2a1ff31a10254f3c817054ae4"},
|
||||
{file = "cffi-1.14.0-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:95cd16d3dee553f882540c1ffe331d085c9e629499ceadfbda4d4fde635f4b7d"},
|
||||
{file = "cffi-1.14.0-cp36-cp36m-manylinux1_i686.whl", hash = "sha256:66e41db66b47d0d8672d8ed2708ba91b2f2524ece3dee48b5dfb36be8c2f21dc"},
|
||||
{file = "cffi-1.14.0-cp36-cp36m-manylinux1_x86_64.whl", hash = "sha256:028a579fc9aed3af38f4892bdcc7390508adabc30c6af4a6e4f611b0c680e6ac"},
|
||||
{file = "cffi-1.14.0-cp36-cp36m-win32.whl", hash = "sha256:cef128cb4d5e0b3493f058f10ce32365972c554572ff821e175dbc6f8ff6924f"},
|
||||
{file = "cffi-1.14.0-cp36-cp36m-win_amd64.whl", hash = "sha256:337d448e5a725bba2d8293c48d9353fc68d0e9e4088d62a9571def317797522b"},
|
||||
{file = "cffi-1.14.0-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:e577934fc5f8779c554639376beeaa5657d54349096ef24abe8c74c5d9c117c3"},
|
||||
{file = "cffi-1.14.0-cp37-cp37m-manylinux1_i686.whl", hash = "sha256:62ae9af2d069ea2698bf536dcfe1e4eed9090211dbaafeeedf5cb6c41b352f66"},
|
||||
{file = "cffi-1.14.0-cp37-cp37m-manylinux1_x86_64.whl", hash = "sha256:14491a910663bf9f13ddf2bc8f60562d6bc5315c1f09c704937ef17293fb85b0"},
|
||||
{file = "cffi-1.14.0-cp37-cp37m-win32.whl", hash = "sha256:c43866529f2f06fe0edc6246eb4faa34f03fe88b64a0a9a942561c8e22f4b71f"},
|
||||
{file = "cffi-1.14.0-cp37-cp37m-win_amd64.whl", hash = "sha256:2089ed025da3919d2e75a4d963d008330c96751127dd6f73c8dc0c65041b4c26"},
|
||||
{file = "cffi-1.14.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:3b911c2dbd4f423b4c4fcca138cadde747abdb20d196c4a48708b8a2d32b16dd"},
|
||||
{file = "cffi-1.14.0-cp38-cp38-manylinux1_i686.whl", hash = "sha256:7e63cbcf2429a8dbfe48dcc2322d5f2220b77b2e17b7ba023d6166d84655da55"},
|
||||
{file = "cffi-1.14.0-cp38-cp38-manylinux1_x86_64.whl", hash = "sha256:3d311bcc4a41408cf5854f06ef2c5cab88f9fded37a3b95936c9879c1640d4c2"},
|
||||
{file = "cffi-1.14.0-cp38-cp38-win32.whl", hash = "sha256:675686925a9fb403edba0114db74e741d8181683dcf216be697d208857e04ca8"},
|
||||
{file = "cffi-1.14.0-cp38-cp38-win_amd64.whl", hash = "sha256:00789914be39dffba161cfc5be31b55775de5ba2235fe49aa28c148236c4e06b"},
|
||||
{file = "cffi-1.14.0.tar.gz", hash = "sha256:2d384f4a127a15ba701207f7639d94106693b6cd64173d6c8988e2c25f3ac2b6"},
|
||||
]
|
||||
chardet = [
|
||||
{file = "chardet-3.0.4-py2.py3-none-any.whl", hash = "sha256:fc323ffcaeaed0e0a02bf4d117757b98aed530d9ed4531e3e15460124c106691"},
|
||||
{file = "chardet-3.0.4.tar.gz", hash = "sha256:84ab92ed1c4d4f16916e05906b6b75a6c0fb5db821cc65e70cbd64a3e2a5eaae"},
|
||||
]
|
||||
cryptography = [
|
||||
{file = "cryptography-2.8-cp27-cp27m-macosx_10_6_intel.whl", hash = "sha256:fb81c17e0ebe3358486cd8cc3ad78adbae58af12fc2bf2bc0bb84e8090fa5ce8"},
|
||||
{file = "cryptography-2.8-cp27-cp27m-manylinux1_x86_64.whl", hash = "sha256:44ff04138935882fef7c686878e1c8fd80a723161ad6a98da31e14b7553170c2"},
|
||||
{file = "cryptography-2.8-cp27-cp27m-manylinux2010_x86_64.whl", hash = "sha256:369d2346db5934345787451504853ad9d342d7f721ae82d098083e1f49a582ad"},
|
||||
{file = "cryptography-2.8-cp27-cp27m-win32.whl", hash = "sha256:df6b4dca2e11865e6cfbfb708e800efb18370f5a46fd601d3755bc7f85b3a8a2"},
|
||||
{file = "cryptography-2.8-cp27-cp27m-win_amd64.whl", hash = "sha256:7f09806ed4fbea8f51585231ba742b58cbcfbfe823ea197d8c89a5e433c7e912"},
|
||||
{file = "cryptography-2.8-cp27-cp27mu-manylinux1_x86_64.whl", hash = "sha256:58363dbd966afb4f89b3b11dfb8ff200058fbc3b947507675c19ceb46104b48d"},
|
||||
{file = "cryptography-2.8-cp27-cp27mu-manylinux2010_x86_64.whl", hash = "sha256:6ec280fb24d27e3d97aa731e16207d58bd8ae94ef6eab97249a2afe4ba643d42"},
|
||||
{file = "cryptography-2.8-cp34-abi3-macosx_10_6_intel.whl", hash = "sha256:b43f53f29816ba1db8525f006fa6f49292e9b029554b3eb56a189a70f2a40879"},
|
||||
{file = "cryptography-2.8-cp34-abi3-manylinux1_x86_64.whl", hash = "sha256:7270a6c29199adc1297776937a05b59720e8a782531f1f122f2eb8467f9aab4d"},
|
||||
{file = "cryptography-2.8-cp34-abi3-manylinux2010_x86_64.whl", hash = "sha256:de96157ec73458a7f14e3d26f17f8128c959084931e8997b9e655a39c8fde9f9"},
|
||||
{file = "cryptography-2.8-cp34-cp34m-win32.whl", hash = "sha256:02079a6addc7b5140ba0825f542c0869ff4df9a69c360e339ecead5baefa843c"},
|
||||
{file = "cryptography-2.8-cp34-cp34m-win_amd64.whl", hash = "sha256:b0de590a8b0979649ebeef8bb9f54394d3a41f66c5584fff4220901739b6b2f0"},
|
||||
{file = "cryptography-2.8-cp35-cp35m-win32.whl", hash = "sha256:ecadccc7ba52193963c0475ac9f6fa28ac01e01349a2ca48509667ef41ffd2cf"},
|
||||
{file = "cryptography-2.8-cp35-cp35m-win_amd64.whl", hash = "sha256:90df0cc93e1f8d2fba8365fb59a858f51a11a394d64dbf3ef844f783844cc793"},
|
||||
{file = "cryptography-2.8-cp36-cp36m-win32.whl", hash = "sha256:1df22371fbf2004c6f64e927668734070a8953362cd8370ddd336774d6743595"},
|
||||
{file = "cryptography-2.8-cp36-cp36m-win_amd64.whl", hash = "sha256:a518c153a2b5ed6b8cc03f7ae79d5ffad7315ad4569b2d5333a13c38d64bd8d7"},
|
||||
{file = "cryptography-2.8-cp37-cp37m-win32.whl", hash = "sha256:4b1030728872c59687badcca1e225a9103440e467c17d6d1730ab3d2d64bfeff"},
|
||||
{file = "cryptography-2.8-cp37-cp37m-win_amd64.whl", hash = "sha256:d31402aad60ed889c7e57934a03477b572a03af7794fa8fb1780f21ea8f6551f"},
|
||||
{file = "cryptography-2.8-cp38-cp38-win32.whl", hash = "sha256:73fd30c57fa2d0a1d7a49c561c40c2f79c7d6c374cc7750e9ac7c99176f6428e"},
|
||||
{file = "cryptography-2.8-cp38-cp38-win_amd64.whl", hash = "sha256:971221ed40f058f5662a604bd1ae6e4521d84e6cad0b7b170564cc34169c8f13"},
|
||||
{file = "cryptography-2.8.tar.gz", hash = "sha256:3cda1f0ed8747339bbdf71b9f38ca74c7b592f24f65cdb3ab3765e4b02871651"},
|
||||
]
|
||||
decorator = [
|
||||
{file = "decorator-4.4.2-py2.py3-none-any.whl", hash = "sha256:41fa54c2a0cc4ba648be4fd43cff00aedf5b9465c9bf18d64325bc225f08f760"},
|
||||
{file = "decorator-4.4.2.tar.gz", hash = "sha256:e3a62f0520172440ca0dcc823749319382e377f37f140a0b99ef45fecb84bfe7"},
|
||||
]
|
||||
filetype = [
|
||||
{file = "filetype-1.0.6-py2.py3-none-any.whl", hash = "sha256:fd6d0ec56820acccf8c9fb6c3ba7e04a302f6ff6c70bcc09daf4842ae9e2ac30"},
|
||||
{file = "filetype-1.0.6.tar.gz", hash = "sha256:99d2b923921cadbe6e451249091ca7156b4beaee6e741bd711a582d4dd2f2881"},
|
||||
]
|
||||
future = [
|
||||
{file = "future-0.18.2.tar.gz", hash = "sha256:b1bead90b70cf6ec3f0710ae53a525360fa360d306a86583adc6bf83a4db537d"},
|
||||
]
|
||||
idna = [
|
||||
{file = "idna-2.9-py2.py3-none-any.whl", hash = "sha256:a068a21ceac8a4d63dbfd964670474107f541babbd2250d61922f029858365fa"},
|
||||
{file = "idna-2.9.tar.gz", hash = "sha256:7588d1c14ae4c77d74036e8c22ff447b26d0fde8f007354fd48a7814db15b7cb"},
|
||||
]
|
||||
markovify = [
|
||||
{file = "markovify-0.8.0.tar.gz", hash = "sha256:c533a2e1aba8148bb98031b7159e8bf1a276c61db53d2e882ecb74fa5603a4f4"},
|
||||
]
|
||||
mutagen = [
|
||||
{file = "mutagen-1.44.0-py3-none-any.whl", hash = "sha256:1cfc9f40cc0c89f051e3f3dbd5d9057a193c98433cf6c95e02d7f5a395615c01"},
|
||||
{file = "mutagen-1.44.0.tar.gz", hash = "sha256:56065d8a9ca0bc64610a4d0f37e2bd4453381dde3226b8835ee656faa3287be4"},
|
||||
]
|
||||
oauthlib = [
|
||||
{file = "oauthlib-3.1.0-py2.py3-none-any.whl", hash = "sha256:df884cd6cbe20e32633f1db1072e9356f53638e4361bef4e8b03c9127c9328ea"},
|
||||
{file = "oauthlib-3.1.0.tar.gz", hash = "sha256:bee41cc35fcca6e988463cacc3bcb8a96224f470ca547e697b604cc697b2f889"},
|
||||
]
|
||||
pyacoustid = [
|
||||
{file = "pyacoustid-1.1.7.tar.gz", hash = "sha256:07394a8ae84625a0a6fef2d891d19687ff59cd955caaf48097da2826043356fd"},
|
||||
]
|
||||
pycparser = [
|
||||
{file = "pycparser-2.20-py2.py3-none-any.whl", hash = "sha256:7582ad22678f0fcd81102833f60ef8d0e57288b6b5fb00323d101be910e35705"},
|
||||
{file = "pycparser-2.20.tar.gz", hash = "sha256:2d475327684562c3a96cc71adf7dc8c4f0565175cf86b6d7a404ff4c771f15f0"},
|
||||
]
|
||||
python-telegram-bot = [
|
||||
{file = "python-telegram-bot-12.4.2.tar.gz", hash = "sha256:0a97cbca638f949582b4ee326170d2f8d7f4bf559a4e511132bb2203623e04ad"},
|
||||
{file = "python_telegram_bot-12.4.2-py2.py3-none-any.whl", hash = "sha256:d3cffd020af4094d07c11783f875e5c682072ba7f5bc21ce89ff0222f4e6d742"},
|
||||
]
|
||||
pytumblr = [
|
||||
{file = "PyTumblr-0.1.0-py2.py3-none-any.whl", hash = "sha256:a3774d3978bcff2db98f36a2e5d17bb8496ac21157b1b518089adad86d0dca72"},
|
||||
{file = "PyTumblr-0.1.0.tar.gz", hash = "sha256:eaa4d98217df7ab6392fa5d8801f4a2bdcba35bf0fd49328aa3c98e3b231b6f2"},
|
||||
]
|
||||
requests = [
|
||||
{file = "requests-2.23.0-py2.py3-none-any.whl", hash = "sha256:43999036bfa82904b6af1d99e4882b560e5e2c68e5c4b0aa03b655f3d7d73fee"},
|
||||
{file = "requests-2.23.0.tar.gz", hash = "sha256:b3f43d496c6daba4493e7c431722aeb7dbc6288f52a6e04e7b6023b0247817e6"},
|
||||
]
|
||||
requests-oauthlib = [
|
||||
{file = "requests-oauthlib-1.3.0.tar.gz", hash = "sha256:b4261601a71fd721a8bd6d7aa1cc1d6a8a93b4a9f5e96626f8e4d91e8beeaa6a"},
|
||||
{file = "requests_oauthlib-1.3.0-py2.py3-none-any.whl", hash = "sha256:7f71572defaecd16372f9006f33c2ec8c077c3cfa6f5911a9a90202beb513f3d"},
|
||||
{file = "requests_oauthlib-1.3.0-py3.7.egg", hash = "sha256:fa6c47b933f01060936d87ae9327fead68768b69c6c9ea2109c48be30f2d4dbc"},
|
||||
]
|
||||
six = [
|
||||
{file = "six-1.14.0-py2.py3-none-any.whl", hash = "sha256:8f3cd2e254d8f793e7f3d6d9df77b92252b52637291d0f0da013c76ea2724b6c"},
|
||||
{file = "six-1.14.0.tar.gz", hash = "sha256:236bdbdce46e6e6a3d61a337c0f8b763ca1e8717c03b369e87a7ec7ce1319c0a"},
|
||||
]
|
||||
tornado = [
|
||||
{file = "tornado-6.0.4-cp35-cp35m-win32.whl", hash = "sha256:5217e601700f24e966ddab689f90b7ea4bd91ff3357c3600fa1045e26d68e55d"},
|
||||
{file = "tornado-6.0.4-cp35-cp35m-win_amd64.whl", hash = "sha256:c98232a3ac391f5faea6821b53db8db461157baa788f5d6222a193e9456e1740"},
|
||||
{file = "tornado-6.0.4-cp36-cp36m-win32.whl", hash = "sha256:5f6a07e62e799be5d2330e68d808c8ac41d4a259b9cea61da4101b83cb5dc673"},
|
||||
{file = "tornado-6.0.4-cp36-cp36m-win_amd64.whl", hash = "sha256:c952975c8ba74f546ae6de2e226ab3cc3cc11ae47baf607459a6728585bb542a"},
|
||||
{file = "tornado-6.0.4-cp37-cp37m-win32.whl", hash = "sha256:2c027eb2a393d964b22b5c154d1a23a5f8727db6fda837118a776b29e2b8ebc6"},
|
||||
{file = "tornado-6.0.4-cp37-cp37m-win_amd64.whl", hash = "sha256:5618f72e947533832cbc3dec54e1dffc1747a5cb17d1fd91577ed14fa0dc081b"},
|
||||
{file = "tornado-6.0.4-cp38-cp38-win32.whl", hash = "sha256:22aed82c2ea340c3771e3babc5ef220272f6fd06b5108a53b4976d0d722bcd52"},
|
||||
{file = "tornado-6.0.4-cp38-cp38-win_amd64.whl", hash = "sha256:c58d56003daf1b616336781b26d184023ea4af13ae143d9dda65e31e534940b9"},
|
||||
{file = "tornado-6.0.4.tar.gz", hash = "sha256:0fe2d45ba43b00a41cd73f8be321a44936dc1aba233dee979f17a042b83eb6dc"},
|
||||
]
|
||||
unidecode = [
|
||||
{file = "Unidecode-1.1.1-py2.py3-none-any.whl", hash = "sha256:1d7a042116536098d05d599ef2b8616759f02985c85b4fef50c78a5aaf10822a"},
|
||||
{file = "Unidecode-1.1.1.tar.gz", hash = "sha256:2b6aab710c2a1647e928e36d69c21e76b453cd455f4e2621000e54b2a9b8cce8"},
|
||||
]
|
||||
urllib3 = [
|
||||
{file = "urllib3-1.25.8-py2.py3-none-any.whl", hash = "sha256:2f3db8b19923a873b3e5256dc9c2dedfa883e33d87c690d9c7913e1f40673cdc"},
|
||||
{file = "urllib3-1.25.8.tar.gz", hash = "sha256:87716c2d2a7121198ebcb7ce7cccf6ce5e9ba539041cfbaeecfb641dc0bf6acc"},
|
||||
]
|
||||
youtube-dl = [
|
||||
{file = "youtube_dl-2020.3.24-py2.py3-none-any.whl", hash = "sha256:c0be39ea9bca72fa02a0d2d043c5e9bd8ea8e0fe79705e891161d6fcd29da59e"},
|
||||
{file = "youtube_dl-2020.3.24.tar.gz", hash = "sha256:4b03efe439f7cae26eba909821d1df00a9a4eb82741cb2e8b78fe29702bd4633"},
|
||||
]
|
|
@ -1,24 +0,0 @@
|
|||
[tool.poetry]
|
||||
name = "delojza"
|
||||
version = "0.1.0"
|
||||
description = ""
|
||||
authors = ["Tomáš Mládek <t@mldk.cz>"]
|
||||
license = "MIT"
|
||||
|
||||
[tool.poetry.dependencies]
|
||||
python = "^3.8"
|
||||
python-telegram-bot = "^12.4.2"
|
||||
youtube-dl = "^2020"
|
||||
requests = "^2.23.0"
|
||||
filetype = "^1.0.6"
|
||||
mutagen = "^1.44.0"
|
||||
pyacoustid = "^1.1.7"
|
||||
pytumblr = "^0.1.0"
|
||||
markovify = "^0.8.0"
|
||||
unidecode = "^1.1.1"
|
||||
|
||||
[tool.poetry.dev-dependencies]
|
||||
|
||||
[build-system]
|
||||
requires = ["poetry>=0.12"]
|
||||
build-backend = "poetry.masonry.api"
|
|
@ -1,7 +0,0 @@
|
|||
#!/bin/bash
|
||||
DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )"
|
||||
cd ${DIR}
|
||||
trap "kill 0" EXIT
|
||||
|
||||
source ./.venv/bin/activate
|
||||
python delojza.py 2>&1 |tee -a delojza_redirect.log
|
18
util.py
Normal file
18
util.py
Normal file
|
@ -0,0 +1,18 @@
|
|||
from _typeshed import StrPath
|
||||
from datetime import datetime
|
||||
import os
|
||||
import errno
|
||||
|
||||
|
||||
def mkdir_p(path: StrPath) -> None:
|
||||
try:
|
||||
os.makedirs(path)
|
||||
except OSError as exc:
|
||||
if exc.errno == errno.EEXIST and os.path.isdir(path):
|
||||
pass
|
||||
else:
|
||||
raise
|
||||
|
||||
|
||||
def datestr(date: datetime) -> str:
|
||||
return date.strftime("%Y-%m-%d@%H%M")
|
Loading…
Reference in a new issue