Compare commits
4 commits
Author | SHA1 | Date | |
---|---|---|---|
ee7cf637ba | |||
5011077da6 | |||
6311672c9e | |||
902a49dcb2 |
15 changed files with 1263 additions and 1742 deletions
1062
delojza.py
1062
delojza.py
File diff suppressed because it is too large
Load diff
27
markov.py
27
markov.py
|
@ -1,27 +0,0 @@
|
|||
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
611
poetry.lock
generated
|
@ -1,611 +0,0 @@
|
|||
[[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"},
|
||||
]
|
|
@ -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 = "^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
Executable file
704
src/delojza.py
Executable file
|
@ -0,0 +1,704 @@
|
|||
#!/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()
|
0
src/lib/__init__.py
Normal file
0
src/lib/__init__.py
Normal file
42
src/lib/db.py
Normal file
42
src/lib/db.py
Normal file
|
@ -0,0 +1,42 @@
|
|||
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()
|
25
src/lib/markov.py
Normal file
25
src/lib/markov.py
Normal file
|
@ -0,0 +1,25 @@
|
|||
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')
|
25
src/lib/tagging.py
Normal file
25
src/lib/tagging.py
Normal file
|
@ -0,0 +1,25 @@
|
|||
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()
|
43
src/lib/util.py
Normal file
43
src/lib/util.py
Normal file
|
@ -0,0 +1,43 @@
|
|||
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
Normal file
393
src/poetry.lock
generated
Normal file
|
@ -0,0 +1,393 @@
|
|||
[[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"},
|
||||
]
|
24
src/pyproject.toml
Normal file
24
src/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 = "^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"
|
7
src/run.sh
Executable file
7
src/run.sh
Executable file
|
@ -0,0 +1,7 @@
|
|||
#!/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
18
util.py
|
@ -1,18 +0,0 @@
|
|||
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