diff --git a/app/api/routes/admin.py b/app/api/routes/admin.py index 4940782..6a6bc82 100644 --- a/app/api/routes/admin.py +++ b/app/api/routes/admin.py @@ -1153,20 +1153,24 @@ async def s_api_v1_admin_licenses(request): filters.append(UserContent.status.in_(status_values)) applied_filters['status'] = status_values + license_type_field = cast(UserContent.meta['license_type'], String) + if license_type_param: - lt_values: List[int] = [] + lt_values: List[str] = [] for part in license_type_param.split(','): - part = part.strip() - if not part: - continue - try: - lt_values.append(int(part)) - except ValueError: - continue + part = (part or '').strip() + if part: + lt_values.append(part) if lt_values: - license_type_expr = cast(UserContent.meta['license_type'].astext, Integer) - filters.append(license_type_expr.in_(lt_values)) - applied_filters['license_type'] = lt_values + clauses = [] + plain_values = [value for value in lt_values if value.lower() not in {'unknown', 'null'}] + if plain_values: + clauses.append(license_type_field.in_(plain_values)) + if any(value.lower() in {'unknown', 'null'} for value in lt_values): + clauses.append(license_type_field.is_(None)) + if clauses: + filters.append(or_(*clauses)) + applied_filters['license_type'] = lt_values if user_id_param: try: @@ -1291,14 +1295,14 @@ async def s_api_v1_admin_licenses(request): type_counts_rows = (await session.execute(type_stmt)).all() type_counts = {ctype or 'unknown': int(count or 0) for ctype, count in type_counts_rows} - license_type_expr = func.coalesce(cast(UserContent.meta['license_type'].astext, Integer), -1) - license_type_stmt = select(license_type_expr.label('license_type'), func.count()).group_by('license_type') + license_type_expr = func.coalesce(license_type_field, 'unknown') + license_type_stmt = select(license_type_expr.label('license_type'), func.count()).group_by(license_type_expr) if filters: license_type_stmt = license_type_stmt.where(and_(*filters)) license_type_counts_rows = (await session.execute(license_type_stmt)).all() license_type_counts: Dict[str, int] = {} for lt_value, count in license_type_counts_rows: - key = 'unknown' if lt_value in (None, -1) else str(int(lt_value)) + key = 'unknown' if lt_value in (None, 'null', 'None') else str(lt_value) license_type_counts[key] = int(count or 0) items: List[Dict[str, Any]] = [] @@ -1721,7 +1725,7 @@ async def s_api_v1_admin_node_setrole(request): row = (await session.execute(select(KnownNode).where(KnownNode.ip == host))).scalars().first() if not row: return response.json({"error": "NOT_FOUND"}, status=404) - meta = row.meta or {} + meta = {**(row.meta or {})} meta['role'] = role row.meta = meta await session.commit() diff --git a/app/core/models/_telegram/templates/player.py b/app/core/models/_telegram/templates/player.py index dfddc9c..1b73f07 100644 --- a/app/core/models/_telegram/templates/player.py +++ b/app/core/models/_telegram/templates/player.py @@ -1,3 +1,4 @@ +import html from sqlalchemy import and_, select from app.core.models.node_storage import StoredContent from app.core.models.content.user_content import UserContent, UserAction @@ -12,6 +13,7 @@ import urllib from app.core.models.transaction import StarsInvoice from app.core._utils.share_links import build_content_links +from app.core.models.content_v3 import EncryptedContent class PlayerTemplates: @@ -90,14 +92,45 @@ class PlayerTemplates: if cover_content: template_kwargs['photo'] = URLInputFile(cover_content.web_url) + encrypted_cid_candidates = [] + if content_meta: + encrypted_cid_candidates.extend([ + content_meta.get('content_cid'), + content_meta.get('encrypted_cid'), + ]) + if local_content and isinstance(local_content.meta, dict): + encrypted_cid_candidates.append(local_content.meta.get('encrypted_cid')) + if content and content.content_id: + encrypted_cid_candidates.append(content.content_id) + + encrypted_content_row = None + if self.db_session: + for candidate in encrypted_cid_candidates: + if not candidate: + continue + encrypted_content_row = (await self.db_session.execute( + select(EncryptedContent).where(EncryptedContent.encrypted_cid == candidate) + )).scalars().first() + if encrypted_content_row: + break + if not local_content: status_hint = self.user.translated('p_playerContext_contentNotReady') description = (content_metadata_json.get('description') or '').strip() + encrypted_description = (encrypted_content_row.description or '').strip() if encrypted_content_row and encrypted_content_row.description else '' + if not description and encrypted_description: + description = encrypted_description if description: description_block = f"{description}\n" - title = content_metadata_json.get('name') or (local_content.filename if local_content else None) or (content.filename if content else None) or content.cid.serialize_v2() + title = ( + content_metadata_json.get('name') + or (encrypted_content_row.title if encrypted_content_row and encrypted_content_row.title else None) + or (local_content.filename if local_content else None) + or (content.filename if content else None) + or content.cid.serialize_v2() + ) status_block = f"{status_hint}\n" if status_hint else "" @@ -106,6 +139,32 @@ class PlayerTemplates: \t/ p2p content market /
🔴 «открыть в MY»""" + if self.db_session and content: + processing_messages = (await self.db_session.execute( + select(KnownTelegramMessage).where( + and_( + KnownTelegramMessage.type == 'content/processing', + KnownTelegramMessage.chat_id == self._chat_id, + KnownTelegramMessage.bot_id == self.bot_id, + KnownTelegramMessage.deleted == False, + KnownTelegramMessage.content_id == content.id, + ) + ) + )).scalars().all() + + if not local_content: + if not processing_messages: + notice = f"Контент «{html.escape(title)}» обрабатывается. Как только всё будет готово, отправим полную публикацию." + await self.send_message( + notice, + message_type='content/processing', + message_meta={'content_id': content.id}, + content_id=content.id, + ) + else: + for msg in processing_messages: + await self.delete_message(msg.message_id) + make_log("TG-Player", f"Send content {content_type} ({content_encoding}) to chat {self._chat_id}. {cd_log}") kmsgs = (await self.db_session.execute(select(KnownTelegramMessage).where( and_( diff --git a/app/core/models/_telegram/wrapped_bot.py b/app/core/models/_telegram/wrapped_bot.py index 60aa8b6..000990a 100644 --- a/app/core/models/_telegram/wrapped_bot.py +++ b/app/core/models/_telegram/wrapped_bot.py @@ -82,7 +82,7 @@ class Wrapped_CBotChat(T, PlayerTemplates): return result - async def send_message(self, text: str, message_type='common', message_meta={}, **kwargs): + async def send_message(self, text: str, message_type='common', message_meta={}, content_id=None, **kwargs): assert self._chat_id, "No chat_id" try: make_log(self, f"Send message to {self._chat_id}. Text len: {len(text)}", level='debug') @@ -93,7 +93,7 @@ class Wrapped_CBotChat(T, PlayerTemplates): disable_web_page_preview=True, **kwargs ) - return await self.return_result(r, message_type=message_type, message_meta=message_meta) + return await self.return_result(r, message_type=message_type, message_meta=message_meta, content_id=content_id) except BaseException as e: make_log(self, f"Error sending message to {self._chat_id}. Error: {e}", level='warning') return None