diff --git a/app/api/routes/node_storage.py b/app/api/routes/node_storage.py index a9e5c3e..4e2e26b 100644 --- a/app/api/routes/node_storage.py +++ b/app/api/routes/node_storage.py @@ -117,11 +117,6 @@ async def s_api_v1_storage_get(request, file_hash=None): # query_id = str(uuid4().hex()) tempfile_path = os.path.join(UPLOADS_DIR, f"tmp_{content_sha256}") - # async def remove_temp_files(): - # await asyncio.sleep(180) - # if os.path.exists(tempfile_path): - # os.remove(tempfile_path) - accept_type = cid.accept_type or content.meta.get("content_type") if accept_type: if accept_type == "application/json": @@ -141,7 +136,7 @@ async def s_api_v1_storage_get(request, file_hash=None): quality = 95 while quality > 10: cover_image.save(cover_tempfile_path, 'JPEG', quality=quality) - if os.path.getsize(cover_tempfile_path) <= 200 * 1024: # Проверка размера файла в килобайтах + if os.path.getsize(cover_tempfile_path) <= 200 * 1024: break quality -= 5 @@ -160,6 +155,8 @@ async def s_api_v1_storage_get(request, file_hash=None): audio = AudioSegment.from_ogg(file_path) elif file_ext == 'flv': audio = AudioSegment.from_flv(file_path) + else: + audio = None if not audio: try: @@ -183,9 +180,10 @@ async def s_api_v1_storage_get(request, file_hash=None): content_file_bin = await file.read() accept_type = 'audio/mpeg' - make_log(f"Storage", f"Audio {content_sha256} converted successfully") + make_log("Storage", f"Audio {content_sha256} converted successfully") else: tempfile_path = tempfile_path[:-5] + elif content_type == 'image': tempfile_path += "_jpeg" if not os.path.exists(tempfile_path): @@ -195,7 +193,7 @@ async def s_api_v1_storage_get(request, file_hash=None): quality = 95 while quality > 10: image.save(tempfile_path, 'JPEG', quality=quality) - if os.path.getsize(tempfile_path) <= 200 * 1024: # Проверка размера файла в килобайтах + if os.path.getsize(tempfile_path) <= 200 * 1024: break quality -= 5 except BaseException as e: @@ -205,13 +203,52 @@ async def s_api_v1_storage_get(request, file_hash=None): async with aiofiles.open(tempfile_path, "rb") as file: content_file_bin = await file.read() - make_log(f"Storage", f"Image {content_sha256} converted successfully") + make_log("Storage", f"Image {content_sha256} converted successfully") accept_type = 'image/jpeg' else: tempfile_path = tempfile_path[:-5] - return response.raw(body=content_file_bin, **({'content_type': accept_type} if accept_type else {})) + elif content_type == 'video': + # Build a temp path for the video + tempfile_path += "_mp4" + (f"_{seconds_limit}" if seconds_limit else "") + if not os.path.exists(tempfile_path): + try: + # Use ffmpeg to cut or convert to mp4 + if seconds_limit > 0: + # Cut the video to the specified seconds_limit + subprocess.run([ + "ffmpeg", + "-y", + "-i", file_path, + "-t", str(seconds_limit), + "-c:v", "libx264", + "-c:a", "aac", + "-movflags", "+faststart", + tempfile_path + ], check=True) + else: + # Just convert to mp4 (no cutting) + subprocess.run([ + "ffmpeg", + "-y", + "-i", file_path, + "-c:v", "libx264", + "-c:a", "aac", + "-movflags", "+faststart", + tempfile_path + ], check=True) + except BaseException as e: + make_log("Storage", f"Error converting video: {e}" + '\n' + traceback.format_exc(), level="error") + if os.path.exists(tempfile_path): + async with aiofiles.open(tempfile_path, "rb") as file: + content_file_bin = await file.read() + make_log("Storage", f"Video {content_sha256} processed successfully") + accept_type = 'video/mp4' + else: + tempfile_path = tempfile_path[:-4] # remove _mp4 or similar suffix + + return response.raw(body=content_file_bin, **({'content_type': accept_type} if accept_type else {})) async def s_api_v1_storage_decode_cid(request, content_id=None): cid, errmsg = resolve_content(content_id) diff --git a/app/core/models/_telegram/templates/player.py b/app/core/models/_telegram/templates/player.py index c1c49b1..d06ae2d 100644 --- a/app/core/models/_telegram/templates/player.py +++ b/app/core/models/_telegram/templates/player.py @@ -87,6 +87,37 @@ class PlayerTemplates: 'text': self.user.translated('openContractPage_button'), 'url': f"https://tonscan.org/address/{content_meta['item_address']}" }]) + elif content_type == 'video': + # Processing video + video_title = content_metadata_json.get('name', "") + template_kwargs['video'] = URLInputFile(local_content_url) + template_kwargs['caption'] = video_title + template_kwargs['protect_content'] = True + + if cover_content: + # Add thumbnail if cover content is available + template_kwargs['thumbnail'] = URLInputFile(cover_content.web_url) + + if self.bot_id == 1: + # Buttons for sharing and opening in app + inline_keyboard_array.append([{ + 'text': self.user.translated('shareTrack_button'), + 'switch_inline_query': f"C{content.cid.serialize_v2()}", + }]) + inline_keyboard_array.append([{ + 'text': self.user.translated('openTrackInApp_button'), + 'url': f"https://t.me/{CLIENT_TELEGRAM_BOT_USERNAME}/content?startapp={content.cid.serialize_v2()}" + }]) + else: + # Buttons for viewing as a client and opening contract + inline_keyboard_array.append([{ + 'text': self.user.translated('viewTrackAsClient_button'), + 'url': f"https://t.me/{CLIENT_TELEGRAM_BOT_USERNAME}?start=C{content.cid.serialize_v2()}" + }]) + inline_keyboard_array.append([{ + 'text': self.user.translated('openContractPage_button'), + 'url': f"https://tonscan.org/address/{content_meta['item_address']}" + }]) else: local_content = None @@ -104,7 +135,12 @@ class PlayerTemplates: or bool(self.db_session.query(UserContent).filter_by(owner_address=user_wallet_address, status='active', content_id=content.id).first()) ) if not have_access: - template_kwargs['audio'] = URLInputFile(local_content_url + '?seconds_limit=30') + if content_type == 'audio': + # Restrict audio to 30 seconds if user does not have access + template_kwargs['audio'] = URLInputFile(local_content_url + '?seconds_limit=30') + elif content_type == 'video': + # Restrict video to 30 seconds if user does not have access + template_kwargs['video'] = URLInputFile(local_content_url + '?seconds_limit=30') make_log("TG-Player", f"Send content {content_type} ({content_encoding}) to chat {self._chat_id}. {cd_log}") for kmsg in self.db_session.query(KnownTelegramMessage).filter_by(