"""Logic module for work with asset statuses.""" import json import os from datetime import datetime from typing import Any import sentry_sdk from sqlalchemy.exc import SQLAlchemyError from assets.constants import ( api, asset_status as asset_status_constants, asset_types, asset_upload_types, field_const, ) from assets.models import asset_final, asset_status, asset_upload, asset_upload_type from assets.models.asset_upload import get_asset_info_for_track_duration_update from assets.models.release_correction import get_release_correction_by_release_id from assets.models.release_correction_detail import ( set_release_correction_detail_by_track_unique_id, ) from assets.models.track import update_track_duration from assets.utils.time_formatter import get_minutes_and_seconds_from_seconds def map_encoding_state_to_status(encoding_state: str) -> str: """Map encoding state to encoding asset status. Args: encoding_state (str): Encoding state from SNS message Returns str: Encoding status """ encoding_status = asset_status_constants.STATE_STATUS_MAPPING.get( encoding_state.lower(), asset_status_constants.STATUS_ENCODING_UNKNOWN ) return encoding_status def create_status_by_filename( filename: str, status: str, description: str, message: dict[str, Any], timestamp: str, ) -> str: """Save information about asset status. Args: filename (str): Unique source asset filename. status (str): Asset processing status. description (str): Asset processing status description. message (dict): Asset status full message info. timestamp (str): Asset status event timestamp. Returns: str: Saved status info. """ clean_filename, _ = os.path.splitext(filename) asset_upload_info = asset_upload.get_asset_upload( clean_filename, api_version=api.API_VERSION_V2 ) return create_status_by_asset_upload_id( asset_upload_id=asset_upload_info["id"], status=status, description=description, message=message, timestamp=timestamp, ) def create_status_by_asset_upload_id( asset_upload_id: int, status: str, description: str, message: dict[str, Any], timestamp: str, ) -> str: """Save information about asset status. Args: asset_upload_id (int): Asset upload id. status (str): Asset processing status. description (str): Asset processing status description. message (dict): Asset status full message info. timestamp (str): Asset status event timestamp. Returns: str: Saved status info. """ asset_status.create_asset_status( asset_upload_id=asset_upload_id, status=status, status_time=datetime.strptime(timestamp, "%Y-%m-%dT%H:%M:%S.%fZ"), description=description, message=json.dumps(message), ) return str(asset_upload_id) def create_status_and_final_assets( filename: str, status: str, description: str, message: dict[str, Any], timestamp: str, final_assets: list[dict[str, Any]], ) -> None: """Save information about asset status and final assets. Args: filename (str): Unique source asset filename. status (str): Asset processing status. description (str): Asset processing status description. message (dict): Asset status full message info. timestamp (str): Asset status event timestamp. final_assets (list): Final assets info. """ clean_filename, _ = os.path.splitext(filename) asset_upload_info = asset_upload.get_asset_upload( clean_filename, api_version=api.API_VERSION_V2 ) asset_upload_id = int( create_status_by_asset_upload_id( asset_upload_id=asset_upload_info["id"], status=status, description=description, message=message, timestamp=timestamp, ) ) if final_assets: for final_asset in final_assets: asset_type = _select_final_asset_type(final_asset, asset_upload_info) asset_final.create_asset_final( asset_upload_id=asset_upload_id, asset_type=asset_type, asset_subtype=final_asset.get( "asset_subtype", asset_types.SUBTYPE_NONE ), filename=final_asset["key"], bucket=final_asset["bucket"], duration=final_asset.get("duration", 0), channels=final_asset.get("channels"), codec=final_asset.get("codec"), sample_rate=final_asset.get("sample_rate"), bit_rate=final_asset.get("bit_rate"), bit_depth=final_asset.get("bit_depth"), ) if asset_type == "WAV": update_track_duration_in_ar_db(asset_upload_id) def _select_final_asset_type( final_asset: dict[str, Any], asset_upload_info: dict[str, Any] ) -> str | None: asset_upload_type_name = asset_upload_type.resolve_asset_upload_type( int(asset_upload_info[field_const.ASSET_UPLOAD_TYPE_ID]) ) if asset_upload_type_name == asset_upload_types.ATMOS: return asset_types.TYPE_FILE_ATMOS asset_type = final_asset.get("asset_type", None) # ows-transcoding only sends the container of a job which passes # through the encoding_status notification and gets processed here. if "container" in final_asset: container = final_asset.get("container") if container in asset_types.AUDIO_CONTAINER_MAPPING.keys(): asset_type = asset_types.AUDIO_CONTAINER_MAPPING[container] return asset_type def get_current_status(asset_upload_id: int) -> dict[str, Any]: """Return the current status of processing asset. Args: asset_upload_id (int): Asset upload ID. Returns: dict: Asset current status info. """ return asset_status.get_last_asset_status(asset_upload_id) def update_track_duration_in_ar_db(asset_upload_id: int) -> None: """Updates the duration of minutes/seconds in art relations. Args: asset_upload_id (int): The id of the uploaded asset. """ asset_info = get_asset_info_for_track_duration_update(asset_upload_id) # This is in milliseconds duration = asset_info["duration"] track_unique_id = asset_info["track_unique_id"] release_id = asset_info["product_id"] track_length_obj = get_minutes_and_seconds_from_seconds(int(duration / 1000)) if asset_info["is_correction"]: release_correction = get_release_correction_by_release_id(release_id) track_correction_data = { "length_minute": track_length_obj["minutes"], "length_seconds": track_length_obj["seconds"], "last_updated": datetime.now().strftime("%Y-%m-%d %H:%M:%S"), } for key in track_correction_data: try: set_release_correction_detail_by_track_unique_id( release_correction["release_correction_id"], track_unique_id, key, track_correction_data[key], ) except SQLAlchemyError as e: # current logic doesn't break this loop when there's sql exception sentry_sdk.capture_exception(e) else: update_track_duration( track_unique_id, track_length_obj["minutes"], track_length_obj["seconds"] )