requirements.in -> poetry, modularization first phase, remove docker
This commit is contained in:
parent
5011077da6
commit
ee7cf637ba
12 changed files with 570 additions and 210 deletions
|
@ -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
|
|
|
@ -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
|
|
158
src/delojza.py
158
src/delojza.py
|
@ -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
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"
|
|
@ -1,9 +0,0 @@
|
||||||
python-telegram-bot
|
|
||||||
youtube-dl
|
|
||||||
requests
|
|
||||||
filetype
|
|
||||||
mutagen
|
|
||||||
pyacoustid
|
|
||||||
pytumblr
|
|
||||||
markovify
|
|
||||||
unidecode
|
|
|
@ -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
|
|
Loading…
Reference in a new issue