From a836196a474830e907d8d8f059aa60b102b66634 Mon Sep 17 00:00:00 2001 From: user Date: Wed, 10 Apr 2024 11:19:04 +0300 Subject: [PATCH] fixes --- app/client_bot/routers/content.py | 3 + app/core/content/audio.py | 71 ++++++++++++++++++++ app/core/content/image.py | 26 +++++++ app/core/models/content/user_content.py | 1 + app/core/models/node_storage.py | 29 +++++++- locale/en/LC_MESSAGES/sanic_telegram_bot.mo | Bin 2680 -> 2719 bytes locale/en/LC_MESSAGES/sanic_telegram_bot.po | 5 +- 7 files changed, 132 insertions(+), 3 deletions(-) create mode 100644 app/core/content/audio.py create mode 100644 app/core/content/image.py diff --git a/app/client_bot/routers/content.py b/app/client_bot/routers/content.py index 44b7e50..3e6162d 100644 --- a/app/client_bot/routers/content.py +++ b/app/client_bot/routers/content.py @@ -139,6 +139,9 @@ async def t_inline_query_node_content(query: types.InlineQuery, memory=None, use audio_url=decrypted_content.web_url + '?seconds_limit=30', title=title, performer=performer, + caption=user.translated('p_playerContext_preview'), + # audio_duration= + parse_mode='html', reply_markup=get_inline_keyboard([ [{ 'text': user.translated('shareTrack_button'), diff --git a/app/core/content/audio.py b/app/core/content/audio.py new file mode 100644 index 0000000..08d1ffc --- /dev/null +++ b/app/core/content/audio.py @@ -0,0 +1,71 @@ +import os + +from pydub import AudioSegment + +from app.core._config import UPLOADS_DIR +from app.core.logger import make_log +import traceback + + +class AudioContentMixin: + def as_audio_segment(self) -> AudioSegment: + audio = None + open_log = f"StoredContent.as_audio_segment({self.id}): " + '\n' + file_ext = self.filename.split('.')[-1] + if not audio: + try: + if file_ext == 'mp3': + audio = AudioSegment.from_mp3(self.filepath) + elif file_ext == 'wav': + audio = AudioSegment.from_wav(self.filepath) + elif file_ext == 'ogg': + audio = AudioSegment.from_ogg(self.filepath) + elif file_ext == 'flv': + audio = AudioSegment.from_flv(self.filepath) + except BaseException as e: + open_log += f"Error loading audio from file (using encoding): {e}" + '\n' + traceback.format_exc() + + if not audio: + try: + audio = AudioSegment.from_file(self.filepath) + except BaseException as e: + open_log += f"Error loading audio from file: {e}" + '\n' + traceback.format_exc() + + if not audio: + try: + audio = AudioSegment(self.file_bin) + except BaseException as e: + open_log += f"Error loading audio from binary: {e}" + '\n' + traceback.format_exc() + + make_log("Storage", open_log, level="debug") + assert audio, "Can't load audio as AudioSegment" + return audio + + def as_mp3(self, seconds_limit=None): + tempfile_path = os.path.join(UPLOADS_DIR, f"temporary_{self.hash}.mp3") + audio = self.as_audio_segment() + if seconds_limit: + seconds_limit = int(seconds_limit) + tempfile_path += f"_f{seconds_limit}" + + if not os.path.exists(tempfile_path): + try: + cover_content = self.__class__.from_cid(self.meta.get('cover_cid')) + cover_tempfile_path = cover_content.as_jpeg() + except BaseException as e: + make_log("Storage", f"Error getting cover content: {e}", level="debug") + cover_content = None + cover_tempfile_path = None + + try: + audio = audio[:seconds_limit * 1000] if seconds_limit else audio + audio.export(tempfile_path, format="mp3", cover=cover_tempfile_path) + except BaseException as e: + make_log("Storage", f"Error converting audio: {e}" + '\n' + traceback.format_exc(), level="error") + + assert os.path.exists(tempfile_path), "Can't convert audio to mp3" + + return tempfile_path + + + diff --git a/app/core/content/image.py b/app/core/content/image.py new file mode 100644 index 0000000..96d9d21 --- /dev/null +++ b/app/core/content/image.py @@ -0,0 +1,26 @@ +import os + +from PIL import Image + +from app.core._config import UPLOADS_DIR +from app.core.logger import make_log +import traceback + + +class ImageContentMixin: + def as_jpeg(self) -> str: + tempfile_path = os.path.join(UPLOADS_DIR, f"temporary_{self.hash}.jpeg") + if not os.path.exists(tempfile_path): + cover_image = Image.open(self.filepath) + cover_image = cover_image.convert('RGB') + quality = 95 + while quality > 10: + cover_image.save(tempfile_path, 'JPEG', quality=quality) + if os.path.getsize(tempfile_path) <= 200 * 1024: + break + + quality -= 5 + + assert os.path.exists(tempfile_path), "Image not found" + + return tempfile_path diff --git a/app/core/models/content/user_content.py b/app/core/models/content/user_content.py index 9ec2caa..4f1d4e0 100644 --- a/app/core/models/content/user_content.py +++ b/app/core/models/content/user_content.py @@ -28,6 +28,7 @@ class UserContent(AlchemyBase, UserContentIndexationMixin): wallet_connection = relationship('WalletConnection', uselist=False, foreign_keys=[wallet_connection_id]) content = relationship('StoredContent', uselist=False, foreign_keys=[content_id]) + class UserAction(AlchemyBase): __tablename__ = 'users_actions' diff --git a/app/core/models/node_storage.py b/app/core/models/node_storage.py index 1ebfd2b..0a07463 100644 --- a/app/core/models/node_storage.py +++ b/app/core/models/node_storage.py @@ -7,11 +7,13 @@ from app.core.logger import make_log from app.core._config import UPLOADS_DIR, PROJECT_HOST import os from app.core.content.content_id import ContentId +from app.core.content.audio import AudioContentMixin +from app.core.content.image import ImageContentMixin # from app.core.models.content.indexation_mixins import NodeStorageIndexationMixin from .base import AlchemyBase -class StoredContent(AlchemyBase): +class StoredContent(AlchemyBase, AudioContentMixin): __tablename__ = 'node_storage' id = Column(Integer, autoincrement=True, primary_key=True) @@ -68,6 +70,31 @@ class StoredContent(AlchemyBase): return bool(self.key_id or self.decrypted_content_id) + def open_content(self, db_session, content_type=None): + try: + # Получение StoredContent в прод-виде с указанием типа данных и доступный для перевода в другие форматы + decrypted_content = self if not self.encrypted else None + encrypted_content = self if self.encrypted else None + content_type = None + if not decrypted_content: + decrypted_content = db_session.query(StoredContent).filter(StoredContent.id == self.decrypted_content_id).first() + else: + encrypted_content = db_session.query(StoredContent).filter(StoredContent.decrypted_content_id == self.id).first() + + assert decrypted_content, "Can't get decrypted content" + assert encrypted_content, "Can't get encrypted content" + content_type = content_type or decrypted_content.json_format()['content_type'] + content_type, content_encoding = content_type.split('/') + + return { + 'encrypted_content': encrypted_content, + 'decrypted_content': decrypted_content, + 'content_type': content_type or 'application/x-binary' + } + except BaseException as e: + make_log("NodeStorage.open_content", f"Can't open content: {self.id} {e}", level='error') + raise e + def json_format(self): extra_fields = {} if self.btfs_cid: diff --git a/locale/en/LC_MESSAGES/sanic_telegram_bot.mo b/locale/en/LC_MESSAGES/sanic_telegram_bot.mo index 195f63507b5e143d72421781849496f1b8fc8d24..75abcd42f294c44be9176ad0835992889027adc8 100644 GIT binary patch delta 143 zcmew%GGBB<4Wn-#0|Ub^4h9BAAl=Ccp;rUx5Fr07kmd%`N?Z&KMnGB*NDBbzL?F!v zq>F$wPzggLkQN5g-J4G`PG{HP;<8Dy3(3eVR!C0FQz%KyPE{x^P$Rib8UJUP)?R G2?GEyNg7iC diff --git a/locale/en/LC_MESSAGES/sanic_telegram_bot.po b/locale/en/LC_MESSAGES/sanic_telegram_bot.po index 1501c82..0e02e43 100644 --- a/locale/en/LC_MESSAGES/sanic_telegram_bot.po +++ b/locale/en/LC_MESSAGES/sanic_telegram_bot.po @@ -128,7 +128,8 @@ msgstr "⚠️ Unsupported content" #: app/core/models/_telegram/templates/player.py:111 msgid "p_playerContext_purchaseRequested" msgstr "Confirm the purchase in your wallet. After that, you will be able to " -"listen to the full track version." +"listen to the full track version.\n\n" +"This can take up to few minutes" #: app/core/models/_telegram/templates/player.py:114 msgid "buyTrackListenLicense_button" @@ -149,7 +150,7 @@ msgstr "Error: content price is not set" #: app/client_bot/routers/content.py:133 msgid "viewTrack_button" -msgstr "View track" +msgstr "Buy track" #: app/client_bot/routers/content.py:138 msgid "cancelPurchase_button"