Skip to content

Commit

Permalink
Merge pull request #85 from remia/feature/dcdn_parse
Browse files Browse the repository at this point in the history
Naming convention check improvements
  • Loading branch information
remia authored Apr 4, 2019
2 parents e5ca64e + 96c415e commit 7f6b83f
Show file tree
Hide file tree
Showing 4 changed files with 59 additions and 40 deletions.
26 changes: 15 additions & 11 deletions clairmeta/dcp_check_isdcf_dcnc.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,8 @@ def run_checks(self):
valid, fields = self.run_check(self.check_dcnc_compliance, source)
if valid:
checks = self.find_check('dcnc_field')
[self.run_check(check, source, fields) for check in checks]
[self.run_check(check, source, fields, message="{}".format(
source['FileName'])) for check in checks]

return self.check_executions

Expand Down Expand Up @@ -149,8 +150,7 @@ def check_dcnc_field_claim_immersive_sound(self, playlist, fields):
immersive = fields['AudioType'].get('ImmersiveSound')
auxdatas = list(list_cpl_assets(
playlist,
filters=['AuxData'],
required_keys=['Probe']))
filters=['AuxData']))

if immersive and not auxdatas:
raise CheckException("ContentTitle claims immersive audio ({}) "
Expand Down Expand Up @@ -208,11 +208,15 @@ def check_dcnc_field_claim_eclaircolor(self, playlist, fields):
raise CheckException("CPL imply EclairColor but ContentTitle miss "
"EC ContentType field")

# TODO : this check don't work for multi-CPL packages
# def check_dcnc_field_claim_packagetype(self, playlist, fields):
# """ DCP type (OV / VF) coherence check. """
# package = fields['PackageType'].get('Type')
# dcp_package = self.dcp.package_type
# if package and dcp_package != package:
# raise CheckException(
# "ContentTitle claims {} but DCP is not".format(package))
def check_dcnc_field_claim_packagetype(self, playlist, fields):
""" DCP type (OV / VF) coherence check. """
package = fields['PackageType'].get('Type')
dcp_package = self.dcp.package_type

if package and package == 'OV' and dcp_package != package:
raise CheckException(
"ContentTitle claims OV but DCP is not complete")

if package and package == 'VF' and dcp_package != package:
raise CheckException(
"ContentTitle claims VF but DCP is complete")
3 changes: 1 addition & 2 deletions clairmeta/dcp_parse.py
Original file line number Diff line number Diff line change
Expand Up @@ -99,8 +99,7 @@ def cpl_parse(path):
def cpl_dcnc_parse(cpl_node):
""" Extract information from ContentTitle """
fields, errors = parse_isdcf_string(cpl_node.get('ContentTitleText'))
if not errors:
cpl_node["NamingConvention"] = fields
cpl_node["NamingConvention"] = fields


def cpl_reels_parse(cpl_node):
Expand Down
2 changes: 1 addition & 1 deletion clairmeta/settings.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@

DCP_SETTINGS = {
# ISDCF Naming Convention enforced
'naming_convention': '9.3',
'naming_convention': '9.6',
# Recognized XML namespaces
'xmlns': {
'xml': 'http://www.w3.org/XML/1998/namespace',
Expand Down
68 changes: 42 additions & 26 deletions clairmeta/utils/isdcf.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,11 +24,11 @@
]

RULES = {
'9.3': {
'9.6': {
'FilmTitle': r'(^[a-zA-Z0-9-]{1,14}$)',
'ContentType':
r'(^'
'(?P<Type>FTR|TLR|TSR|PRO|TST|RTG-F|RTG-T|SHR|ADV|XSN|PSA|POL)'
'(?P<Type>FTR|EPS|TLR|TSR|PRO|TST|RTG-F|RTG-T|SHR|ADV|XSN|PSA|POL)'
'(-(?P<Version>\d))?'
'(-(?P<Temporary>Temp))?'
'(-(?P<PreRelease>Pre))?'
Expand Down Expand Up @@ -59,11 +59,12 @@
'$)',
'AudioType':
r'(^'
'(?P<Channels>(10|20|51|61|71|MOS))'
'(?P<Channels>(10|20|51|71|MOS))'
'(-(?P<HearingImpaired>HI))?'
'(-(?P<VisionImpaired>VI))?'
'(-(?P<ImmersiveSound>(ATMOS|AURO|DTS-X)))?'
'(-(?P<MotionSimulator>DBOX))?'
'(-(?P<SignLanguage>SL))?'
'(-(?P<ImmersiveSound>(ATMOS|Atmos|AURO|DTS-X)))?'
'(-(?P<MotionSimulator>(DBOX|Dbox)))?'
'$)',
'Resolution': r'(^2K|4K$)',
'Studio': r'(^[A-Z0-9]{2,4}$)',
Expand Down Expand Up @@ -93,6 +94,7 @@
'Caption': False,
'HearingImpaired': False,
'VisionImpaired': False,
'SignLanguage': False,
'ImmersiveSound': False,
'MotionSimulator': False,
}
Expand Down Expand Up @@ -121,12 +123,6 @@ def parse_isdcf_string(str):
error_list.append("ContentTitle invalid type")
return fields_dict, error_list

fields_list = str.split('_')
if len(fields_list) != 12:
error_list.append("ContentTitle must have 12 parts, {} found".format(
len(fields_list)))
return fields_dict, error_list

# Sort the fields to respect DCNC order
# Note : in python3 we can declare an OrderedDict({...}) and the field
# order is preserved so this is not needed, but not in python 2.7
Expand All @@ -135,27 +131,47 @@ def parse_isdcf_string(str):
six.iteritems(RULES[dcnc_version]),
key=lambda f: RULES_ORDER.index(f[0])))

# Basic regex checking
fields_dict = init_dict_isdcf(rules)

for field, (name, regex) in zip(fields_list, six.iteritems(rules)):
pattern = re.compile(regex)
match = re.match(pattern, field)
fields_dict[name] = {}
fields_dict[name]['Value'] = field

if match:
fields_dict[name].update(match.groupdict(DEFAULT))
else:
fields_dict[name].update({
k: DEFAULT for k in pattern.groupindex.keys()})
error_list.append("ContentTitle Part {} : {} don't conform with "
"ISDCF naming convention version {}".format(
name, field, dcnc_version))
fields_list = str.split('_')
if len(fields_list) != 12:
error_list.append("ContentTitle must have 12 parts, {} found".format(
len(fields_list)))
else:
for field, (name, regex) in zip(fields_list, six.iteritems(rules)):
pattern = re.compile(regex)
match = re.match(pattern, field)
fields_dict[name]['Value'] = field

if match:
fields_dict[name].update(match.groupdict(DEFAULT))
else:
error_list.append("ContentTitle Part {} : {} don't conform "
"with ISDCF naming convention version {}"
.format(name, field, dcnc_version))

fields_dict = post_parse_isdcf(fields_dict)
return fields_dict, error_list


def init_dict_isdcf(rules):
""" Initialize naming convention metadata dictionary.
Args:
rules (dict): Dictionary of the rules.
"""
res = {}

for (name, regex) in six.iteritems(rules):
pattern = re.compile(regex)

res[name] = {}
res[name]['Value'] = ''
res[name].update({k: DEFAULT for k in pattern.groupindex.keys()})

return res


def post_parse_isdcf(fields):
""" Use additional deduction rules to augment dictionary.
Expand Down

0 comments on commit 7f6b83f

Please sign in to comment.