diff --git a/src/ffx/media_descriptor_change_set.py b/src/ffx/media_descriptor_change_set.py index a5448bc..093542b 100644 --- a/src/ffx/media_descriptor_change_set.py +++ b/src/ffx/media_descriptor_change_set.py @@ -1,5 +1,6 @@ import click +from ffx.iso_language import IsoLanguage from ffx.media_descriptor import MediaDescriptor from ffx.track_descriptor import TrackDescriptor @@ -117,7 +118,11 @@ class MediaDescriptorChangeSet(): sourceTrackDescriptor: TrackDescriptor = None): sourceTrackTags = sourceTrackDescriptor.getTags() if sourceTrackDescriptor is not None else {} - targetTrackTags = targetTrackDescriptor.getTags() if targetTrackDescriptor is not None else {} + targetTrackTags = ( + self.normalizeTrackTags(targetTrackDescriptor.getTags()) + if targetTrackDescriptor is not None + else {} + ) trackCompareResult = {} @@ -142,6 +147,25 @@ class MediaDescriptorChangeSet(): return trackCompareResult + def normalizeTrackTagValue(self, tagKey, tagValue): + if tagKey != "language": + return tagValue + + if isinstance(tagValue, IsoLanguage): + return tagValue.threeLetter() + + trackLanguage = IsoLanguage.findThreeLetter(str(tagValue)) + if trackLanguage != IsoLanguage.UNDEFINED: + return trackLanguage.threeLetter() + + return tagValue + + def normalizeTrackTags(self, trackTags: dict): + return { + tagKey: self.normalizeTrackTagValue(tagKey, tagValue) + for tagKey, tagValue in trackTags.items() + } + def generateDispositionTokens(self): """ @@ -243,7 +267,7 @@ class MediaDescriptorChangeSet(): addedTracks: dict = self.__changeSetObj[MediaDescriptorChangeSet.TRACKS_KEY][DIFF_ADDED_KEY] trackDescriptor: TrackDescriptor for trackDescriptor in addedTracks.values(): - for tagKey, tagValue in trackDescriptor.getTags().items(): + for tagKey, tagValue in self.normalizeTrackTags(trackDescriptor.getTags()).items(): if not tagKey in self.__removeTrackKeys: metadataTokens += [f"-metadata:s:{trackDescriptor.getType().indicator()}" + f":{trackDescriptor.getSubIndex()}", @@ -267,7 +291,7 @@ class MediaDescriptorChangeSet(): trackDescriptor = self.__targetTrackDescriptorsByIndex[trackIndex] - for tagKey, tagValue in outputTrackTags.items(): + for tagKey, tagValue in self.normalizeTrackTags(outputTrackTags).items(): metadataTokens += [f"-metadata:s:{trackDescriptor.getType().indicator()}" + f":{trackDescriptor.getSubIndex()}", f"{tagKey}={tagValue}"] @@ -285,7 +309,7 @@ class MediaDescriptorChangeSet(): } | unchangedTrackTags ) - for tagKey, tagValue in preservedTrackTags.items(): + for tagKey, tagValue in self.normalizeTrackTags(preservedTrackTags).items(): metadataTokens += [f"-metadata:s:{trackDescriptor.getType().indicator()}" + f":{trackDescriptor.getSubIndex()}", f"{tagKey}={tagValue}"] diff --git a/tests/unit/test_media_descriptor_change_set.py b/tests/unit/test_media_descriptor_change_set.py index bf9be09..93c641a 100644 --- a/tests/unit/test_media_descriptor_change_set.py +++ b/tests/unit/test_media_descriptor_change_set.py @@ -27,6 +27,64 @@ class StaticConfig: class MediaDescriptorChangeSetTests(unittest.TestCase): + def test_non_primary_source_language_code_is_normalized_in_changed_track_metadata(self): + context = { + "logger": get_ffx_logger(), + "config": StaticConfig({}), + } + + source_track = TrackDescriptor( + index=0, + source_index=0, + sub_index=0, + track_type=TrackType.AUDIO, + tags={"language": "ger", "title": "German Main"}, + ) + target_track = TrackDescriptor( + index=0, + source_index=0, + sub_index=0, + track_type=TrackType.AUDIO, + tags={"language": "ger", "title": "German Main"}, + ) + + change_set = MediaDescriptorChangeSet( + context, + MediaDescriptor(track_descriptors=[target_track]), + MediaDescriptor(track_descriptors=[source_track]), + ) + + metadata_tokens = change_set.generateMetadataTokens() + + self.assertIn("-metadata:s:a:0", metadata_tokens) + self.assertIn("language=deu", metadata_tokens) + self.assertNotIn("language=ger", metadata_tokens) + + def test_target_only_track_language_metadata_uses_primary_code(self): + context = { + "logger": get_ffx_logger(), + "config": StaticConfig({}), + } + + target_track = TrackDescriptor( + index=0, + source_index=0, + sub_index=0, + track_type=TrackType.AUDIO, + tags={"language": "ger", "title": "German Main"}, + ) + + change_set = MediaDescriptorChangeSet( + context, + MediaDescriptor(track_descriptors=[target_track]), + ) + + metadata_tokens = change_set.generateMetadataTokens() + + self.assertIn("-metadata:s:a:0", metadata_tokens) + self.assertIn("language=deu", metadata_tokens) + self.assertNotIn("language=ger", metadata_tokens) + def test_external_subtitle_preserves_source_only_tags_except_removed_keys(self): context = { "logger": get_ffx_logger(), @@ -79,6 +137,40 @@ class MediaDescriptorChangeSetTests(unittest.TestCase): self.assertNotIn("BPS=remove-me", metadata_tokens) self.assertIn("BPS=", metadata_tokens) + def test_external_subtitle_normalizes_preserved_source_language_metadata(self): + context = { + "logger": get_ffx_logger(), + "config": StaticConfig({}), + } + + source_track = TrackDescriptor( + index=0, + source_index=0, + sub_index=0, + track_type=TrackType.SUBTITLE, + tags={"language": "ger", "title": "German Subtitle"}, + ) + target_track = TrackDescriptor( + index=0, + source_index=0, + sub_index=0, + track_type=TrackType.SUBTITLE, + tags={}, + external_source_file="/tmp/external-subtitle.vtt", + ) + + change_set = MediaDescriptorChangeSet( + context, + MediaDescriptor(track_descriptors=[target_track]), + MediaDescriptor(track_descriptors=[source_track]), + ) + + metadata_tokens = change_set.generateMetadataTokens() + + self.assertIn("-metadata:s:s:0", metadata_tokens) + self.assertIn("language=deu", metadata_tokens) + self.assertNotIn("language=ger", metadata_tokens) + def test_target_only_tracks_still_emit_remove_tokens_for_configured_stream_keys(self): context = { "logger": get_ffx_logger(),