"""TranscodingRule Model. This TranscodingRule model uses sqlalchemy. It's used to store information about transcoding rules. """ from typing import Any from owsresponse import response from sentry_sdk import capture_exception from sqlalchemy import Column, ColumnElement, String, or_ from sqlalchemy.dialects.mysql import INTEGER from sqlalchemy.exc import SQLAlchemyError from transcoding.connectors import mysql from transcoding.constants import error INPUT_AUDIO_META_PARAMETERS = { "input_container", "input_channels", "input_codec", "input_sample_rate", "input_bit_depth", } class TranscodingRule(mysql.BaseModel): """Table definition for transcoding_rule table. The transcoding rule entry contains information about input parameters filter for uploaded assets and output configuration for transcoding job. Transcoding rules are associated with presets. Transcoding properties clarification: channels: Number of channels, e.g.: 1 or 2 codec: Codec which has been used for audio encoding, e.g.: pcm, .. container: Container format sample_rate: Number of samples per second in Hz, e.g.: 44100, 48000,.. bit_rate: Number of bits per second in bit/s, e.g.: 1411200, 1519552,. bit_depth: Number of bits of information in each sample e.g.: 16, 24 If these properties are not specified, we use the values from the source file. """ __tablename__ = "transcoding_rule" transcoding_rule_id = Column( INTEGER(unsigned=True), primary_key=True, autoincrement=True ) preset_id = Column(INTEGER(unsigned=True), nullable=False) input_container = Column(String(255), default=None, nullable=True) input_channels = Column(INTEGER(display_width=1, unsigned=True), nullable=True) input_codec = Column(String(255), default=None, nullable=True) input_sample_rate = Column(INTEGER(11), default=None, nullable=True) input_bit_depth = Column(INTEGER(11), default=None, nullable=True) output_container = Column(String(255), nullable=False) output_channels = Column(INTEGER(display_width=1, unsigned=True), nullable=True) output_codec = Column(String(255), default=None, nullable=True) output_sample_rate = Column(INTEGER(11), default=None, nullable=True) output_bit_rate = Column(INTEGER(11), default=None, nullable=True) output_bit_depth = Column(INTEGER(11), default=None, nullable=True) output_key = Column(String(255), default=None, nullable=True) def as_dict(self) -> dict[str, Any]: """Return object as dict. Returns: dict: Dictionary representation of object. """ transcoding_job_dict = { "transcoding_rule_id": self.transcoding_rule_id, "preset_id": self.preset_id, "input_container": self.input_container, "input_channels": self.input_channels, "input_codec": self.input_codec, "input_sample_rate": self.input_sample_rate, "input_bit_depth": self.input_bit_depth, "output_container": self.output_container, "output_channels": self.output_channels, "output_codec": self.output_codec, "output_sample_rate": self.output_sample_rate, "output_bit_rate": self.output_bit_rate, "output_bit_depth": self.output_bit_depth, "output_key": self.output_key, } return transcoding_job_dict def get_transcoding_rules_by_preset_id(preset_id: int) -> response.Response: """Return list of transcoding rules info by preset_id. Args: preset_id (int): preset id. Returns: response.Response: List of TranscodingRules.as_dict() in message attribute or error response. """ try: with mysql.db_session() as session: filters = [(TranscodingRule.preset_id == preset_id)] transcoding_rules = session.query(TranscodingRule).filter(*filters).all() result_data = [entry.as_dict() for entry in transcoding_rules] return response.Response(message=result_data) except SQLAlchemyError as e: capture_exception(e) return response.create_fatal_response(e.args) def get_transcoding_rule_by_input_parameters_filter( preset_id: int, input_params_filters: dict[str, Any] ) -> response.Response: """Return transcoding rule entry by preset_id and input_parameters filter. Args: preset_id (int): preset id. input_params_filters (dict): Dictionary contains transcoding parameters of uploaded(source) asset. Returns: response.Response: TranscodingRule.as_dict() in message attribute or error response. """ try: with mysql.db_session() as session: transcoding_params_filters = _prepare_filters(input_params_filters) if not transcoding_params_filters: error_message = ( error.ERROR_INVALID_TRANSCODING_RULE_FILTER_MESSAGE.format( INPUT_AUDIO_META_PARAMETERS ) ) return response.create_fatal_response(message=error_message) filters = [ (TranscodingRule.preset_id == preset_id), *transcoding_params_filters, ] transcoding_rules = session.query(TranscodingRule).filter(*filters).all() result_data = [entry.as_dict() for entry in transcoding_rules] return response.Response(result_data) except SQLAlchemyError as e: capture_exception(e) return response.create_fatal_response(e.args) def _prepare_filters( input_params_filters: dict[str, Any], ) -> list[ColumnElement[bool]]: """Prepare filter for transcoding rule matching. Args: input_params_filters (dict): Dictionary contains transcoding parameters of uploaded(source) asset. Returns: list: List of filters for TranscodingRule. """ result_filters = [] for key, value in input_params_filters.items(): input_rule_key = "input_{}".format(key) if input_rule_key in INPUT_AUDIO_META_PARAMETERS: result_filters.append( or_( getattr(TranscodingRule, input_rule_key) == value, getattr(TranscodingRule, input_rule_key).is_(None), ) ) return result_filters