import re import typing from decimal import Decimal from knowit.core import Configurable from knowit.core import Property from knowit.utils import round_decimal class VideoCodec(Configurable[str]): """Video Codec handler.""" @classmethod def _extract_key(cls, value) -> str: key = value.upper().split('/')[-1] if key.startswith('V_'): key = key[2:] return key.split(' ')[-1] class VideoDimensions(Property[int]): """Dimensions property.""" def __init__(self, *args: str, dimension='width' or 'height', **kwargs): """Initialize the object.""" super().__init__(*args, **kwargs) self.dimension = dimension dimensions_re = re.compile(r'(?P\d+)x(?P\d+)') def handle(self, value, context) -> typing.Optional[int]: """Handle ratio.""" match = self.dimensions_re.match(value) if match: match_dict = match.groupdict() try: value = match_dict[self.dimension] except KeyError: pass else: return int(value) self.report(value, context) return None class VideoEncoder(Configurable): """Video Encoder property.""" class VideoHdrFormat(Configurable): """Video HDR Format property.""" class VideoProfile(Configurable[str]): """Video Profile property.""" @classmethod def _extract_key(cls, value) -> str: return value.upper().split('@')[0] class VideoProfileLevel(Configurable[str]): """Video Profile Level property.""" @classmethod def _extract_key(cls, value) -> typing.Union[str, bool]: values = str(value).upper().split('@') if len(values) > 1: value = values[1] return value # There's no level, so don't warn or report it return False class VideoProfileTier(Configurable[str]): """Video Profile Tier property.""" @classmethod def _extract_key(cls, value) -> typing.Union[str, bool]: values = str(value).upper().split('@') if len(values) > 2: return values[2] # There's no tier, so don't warn or report it return False class Ratio(Property[Decimal]): """Ratio property.""" def __init__(self, *args: str, unit=None, **kwargs): """Initialize the object.""" super().__init__(*args, **kwargs) self.unit = unit ratio_re = re.compile(r'(?P\d+)[:/](?P\d+)') def handle(self, value, context) -> typing.Optional[Decimal]: """Handle ratio.""" match = self.ratio_re.match(value) if match: width, height = match.groups() if (width, height) == ('0', '1'): # identity return Decimal('1.0') if height: result = round_decimal(Decimal(width) / Decimal(height), min_digits=1, max_digits=3) if self.unit: result *= self.unit return result self.report(value, context) return None class ScanType(Configurable[str]): """Scan Type property."""