1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
|
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<width>\d+)x(?P<height>\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<width>\d+)[:/](?P<height>\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."""
|