requirements.in -> poetry, modularization first phase, remove docker

This commit is contained in:
Tomáš Mládek 2020-03-28 13:55:12 +01:00
parent 5011077da6
commit ee7cf637ba
12 changed files with 570 additions and 210 deletions

View file

@ -1,9 +0,0 @@
FROM python:3.7
RUN apt-get update && apt-get -y install ffmpeg
COPY ./src /app
RUN cd /app && pip install -r requirements.txt
CMD /app/run.sh

View file

@ -1,24 +0,0 @@
version: '3'
#volumes:
# postgres_ksx-radio: {}
services:
# ksx-postgres:
# restart: always
# image: postgres:11
# ports:
# - "5532:5432"
# volumes:
# - postgres_ksx-radio:/var/lib/postgresql/data
# - ../src/db_versions:/docker-entrypoint-initdb.d
# environment:
# - POSTGRES_USER=ksx
# - POSTGRES_PASSWORD=ksx
# - POSTGRES_DB=ksx-radio
delojza:
restart: always
build:
context: ../.
dockerfile: ./docker/delojza/Dockerfile

View file

@ -1,16 +1,13 @@
#!/usr/bin/env python3 #!/usr/bin/env python3
import errno
import logging import logging
import os import os
import pprint import pprint
import re import re
import shutil import shutil
import sqlite3
import subprocess import subprocess
import sys import sys
import tempfile import tempfile
import unicodedata
from configparser import ConfigParser, NoSectionError from configparser import ConfigParser, NoSectionError
from datetime import datetime, timedelta from datetime import datetime, timedelta
from glob import glob from glob import glob
@ -20,73 +17,20 @@ from time import sleep
import acoustid import acoustid
import filetype import filetype
import markovify
import mutagen.id3 import mutagen.id3
import pytumblr import pytumblr
import requests import requests
import telegram import telegram
import youtube_dl import youtube_dl
from mutagen.easyid3 import EasyID3 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 telegram.ext import Updater, CommandHandler, MessageHandler
from unidecode import unidecode
from youtube_dl import DownloadError from youtube_dl import DownloadError
from youtube_dl.version import __version__ as YTDL_VERSION from youtube_dl.version import __version__ as YTDL_VERSION
def mkdir_p(path):
try:
os.makedirs(path)
except OSError as exc:
if exc.errno == errno.EEXIST and os.path.isdir(path):
pass
else:
raise
def datestr(date):
return date.strftime("%Y-%m-%d@%H%M")
class DelojzaDB:
def __init__(self, db_path):
self.db_path = db_path
self.db = None
def initialize(self):
if self.db is None:
self.db = sqlite3.connect(self.db_path)
def get_protected_tags(self):
results = self.db.execute("SELECT tag FROM tags WHERE protected == 1")
return [res[0] for res in results.fetchall()]
def get_protected_chats(self):
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()
class DelojzaBot: class DelojzaBot:
def __init__(self, tg_api_key, out_dir, redirects=None, tmp_dir=None, db_path=None, protected_password=None, 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): acoustid_key=None, tumblr_name=None, tumblr_keys=None, markov=None):
@ -161,45 +105,8 @@ class DelojzaBot:
f" ({update.message.chat.id}): " + (update.message.text or "<NONE>")) f" ({update.message.chat.id}): " + (update.message.text or "<NONE>"))
@staticmethod @staticmethod
def ytdl_can(url): def datestr(date: datetime):
ies = youtube_dl.extractor.gen_extractors() return date.strftime("%Y-%m-%d@%H%M")
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
# https://github.com/django/django/blob/master/django/utils/text.py#L393
@staticmethod
def sanitize(filepath):
if filepath is None:
return None
filepath = unicodedata.normalize('NFKD', filepath).encode('ascii', 'ignore').decode('ascii')
return re.sub(r'[^\w.()\[\]{}#-]', '_', filepath)
@staticmethod
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
@staticmethod
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()
def _autotag_file(self, filepath, message, info=None): def _autotag_file(self, filepath, message, info=None):
if info is None: if info is None:
@ -261,22 +168,14 @@ class DelojzaBot:
message.reply_text("Tagging as \"{}\" by \"{}\"\nvia {}".format(title, artist, source)) message.reply_text("Tagging as \"{}\" by \"{}\"\nvia {}".format(title, artist, source))
self.logger.info("Tagging {} w/ {} - {} [{}]...".format(filepath, title, artist, source)) self.logger.info("Tagging {} w/ {} - {} [{}]...".format(filepath, title, artist, source))
self._tag_file(filepath, artist, title) tag_file(filepath, artist, title)
@staticmethod
def _get_percent_filled(directory):
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])
# noinspection PyUnusedLocal # noinspection PyUnusedLocal
def download_ytdl(self, urls, out_path, date, message, audio=False, filetitle=None): def download_ytdl(self, urls, out_path, date, message, audio=False, filetitle=None):
ytdl = { ytdl = {
'noplaylist': True, 'noplaylist': True,
'restrictfilenames': True, 'restrictfilenames': True,
'outtmpl': os.path.join(self.tmp_dir, '{}__%(title)s__%(id)s.%(ext)s'.format(datestr(date))) 'outtmpl': os.path.join(self.tmp_dir, '{}__%(title)s__%(id)s.%(ext)s'.format(self.datestr(date)))
} }
if audio: if audio:
ytdl['format'] = 'bestaudio/best' ytdl['format'] = 'bestaudio/best'
@ -316,8 +215,8 @@ class DelojzaBot:
def download_raw(self, urls, out_path, date, message, audio=False, filetitle=None): def download_raw(self, urls, out_path, date, message, audio=False, filetitle=None):
filenames = [] filenames = []
for url in urls: for url in urls:
local_filename = os.path.join(out_path, "{}__{}".format(datestr(date), local_filename = os.path.join(out_path, "{}__{}".format(self.datestr(date),
self.sanitize(filetitle or url.split('/')[-1]))) sanitize(filetitle or url.split('/')[-1])))
final_filename = local_filename final_filename = local_filename
is_mp3 = local_filename.endswith("mp3") is_mp3 = local_filename.endswith("mp3")
@ -374,11 +273,11 @@ class DelojzaBot:
if len(hashtags) == 0 or hashtags[0] not in ('TEXT', 'TXT'): if len(hashtags) == 0 or hashtags[0] not in ('TEXT', 'TXT'):
return return
info_line = self.sanitize("-".join(re.sub(r'#[\w]+', '', message.text).strip().split()[:7])) info_line = sanitize("-".join(re.sub(r'#[\w]+', '', message.text).strip().split()[:7]))
if len(info_line) > 64: if len(info_line) > 64:
info_line = info_line[:64] info_line = info_line[:64]
filename = '{}__{}.txt'.format(datestr(message.date), info_line) filename = '{}__{}.txt'.format(self.datestr(message.date), info_line)
out_dir = self.redirects.get(hashtags[0], self.out_dir) out_dir = self.redirects.get(hashtags[0], self.out_dir)
out_path = os.path.join(out_dir, *hashtags[1:] or ['TEXT']) out_path = os.path.join(out_dir, *hashtags[1:] or ['TEXT'])
file_path = os.path.join(out_path, filename) file_path = os.path.join(out_path, filename)
@ -488,7 +387,7 @@ class DelojzaBot:
file = message.voice.file_id file = message.voice.file_id
if file is not None: if file is not None:
if self.markov and random.random() > .66: if self.markov and random() > .66:
sentence = self.markov.make_sentence() sentence = self.markov.make_sentence()
if sentence: if sentence:
message.reply_text(sentence) message.reply_text(sentence)
@ -501,18 +400,18 @@ class DelojzaBot:
urls = list(map(lambda e: message.parse_entity(e), urls = list(map(lambda e: message.parse_entity(e),
filter(lambda e: e.type == 'url', message.entities))) filter(lambda e: e.type == 'url', message.entities)))
if len(urls) > 0 and self.markov and random.random() > .66: if len(urls) > 0 and self.markov and random() > .66:
sentence = self.markov.make_sentence() sentence = self.markov.make_sentence()
if sentence: if sentence:
message.reply_text(sentence) message.reply_text(sentence)
ytdl_res = False ytdl_res = False
ytdl_urls = [url for url in urls if self.ytdl_can(url)] ytdl_urls = [url for url in urls if ytdl_can(url)]
if len(ytdl_urls) > 0: if len(ytdl_urls) > 0:
ytdl_res = self.handle(ytdl_urls, message, hashtags, self.download_ytdl) ytdl_res = self.handle(ytdl_urls, message, hashtags, self.download_ytdl)
raw_res = False raw_res = False
normal_urls = [url for url in urls if not self.ytdl_can(url)] normal_urls = [url for url in urls if not ytdl_can(url)]
if len(normal_urls) > 0: if len(normal_urls) > 0:
file_urls = [url for url in normal_urls if file_urls = [url for url in normal_urls if
"text" not in requests.head(url).headers.get("Content-Type", "text")] "text" not in requests.head(url).headers.get("Content-Type", "text")]
@ -649,10 +548,10 @@ class DelojzaBot:
for mp3 in mp3s: for mp3 in mp3s:
if reverse: if reverse:
orig_artist, orig_title = self._get_tags(mp3) orig_artist, orig_title = get_tags(mp3)
title, artist = orig_artist, orig_title title, artist = orig_artist, orig_title
self._tag_file(mp3, artist, title) tag_file(mp3, artist, title)
update.message.reply_text("Tagging \"{}\" as \"{}\" by \"{}\"!" update.message.reply_text("Tagging \"{}\" as \"{}\" by \"{}\"!"
.format(mp3[len(out_dir) + 1:], title, artist)) .format(mp3[len(out_dir) + 1:], title, artist))
else: else:
@ -763,27 +662,6 @@ class DelojzaBot:
self.updater.idle() self.updater.idle()
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')
if __name__ == '__main__': if __name__ == '__main__':
logging.basicConfig(level=logging.INFO, format='%(asctime)s - %(name)s - %(levelname)s - %(message)s') logging.basicConfig(level=logging.INFO, format='%(asctime)s - %(name)s - %(levelname)s - %(message)s')

0
src/lib/__init__.py Normal file
View file

42
src/lib/db.py Normal file
View 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
View 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
View 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
View 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
View 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
View 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"

View file

@ -1,9 +0,0 @@
python-telegram-bot
youtube-dl
requests
filetype
mutagen
pyacoustid
pytumblr
markovify
unidecode

View file

@ -1,28 +0,0 @@
#
# This file is autogenerated by pip-compile
# To update, run:
#
# pip-compile
#
asn1crypto==0.24.0 # via cryptography
audioread==2.1.8 # via pyacoustid
certifi==2019.3.9 # via python-telegram-bot, requests
cffi==1.12.3 # via cryptography
chardet==3.0.4 # via requests
cryptography==2.7 # via python-telegram-bot
filetype==1.0.5
future==0.17.1 # via python-telegram-bot, pytumblr
idna==2.8 # via requests
markovify==0.7.1
mutagen==1.42.0
oauthlib==3.0.1 # via requests-oauthlib
pyacoustid==1.1.7
pycparser==2.19 # via cffi
python-telegram-bot==11.1.0
pytumblr==0.0.8
requests-oauthlib==1.2.0 # via pytumblr
requests==2.22.0
six==1.12.0 # via cryptography
unidecode==1.0.23
urllib3==1.25.3 # via requests
youtube-dl==2019.5.20