From ca493338877092c4a46fbf40fc75b2fc636a7a9b Mon Sep 17 00:00:00 2001 From: plodri <132933267+plodri@users.noreply.github.com> Date: Tue, 23 Jul 2024 08:27:39 +0000 Subject: [PATCH 1/4] fix issue #893 add test scenario for the #893 --- jellyfin_kodi/helper/playutils.py | 15 +- tests/test_playutils_settings.py | 303 ++++++++++++++++++++++++++++++ 2 files changed, 311 insertions(+), 7 deletions(-) create mode 100644 tests/test_playutils_settings.py diff --git a/jellyfin_kodi/helper/playutils.py b/jellyfin_kodi/helper/playutils.py index 614f79f0e..d25f31caa 100644 --- a/jellyfin_kodi/helper/playutils.py +++ b/jellyfin_kodi/helper/playutils.py @@ -384,14 +384,15 @@ def get_directplay_video_codec(self): return ",".join(codecs) def get_transcoding_video_codec(self): - codecs = ["h264", "hevc", "h265", "mpeg4", "mpeg2video", "vc1"] + codecs = ["h264", "mpeg4", "mpeg2video", "vc1"] - if settings("transcode_h265.bool"): - codecs.remove("hevc") - codecs.remove("h265") - else: - if settings("videoPreferredCodec") == "H265/HEVC": - codecs.insert(2, codecs.pop(codecs.index("h264"))) + if not settings("transcode_h265.bool"): + codecs.append("hevc") # Add HEVC if transcoding is not forced + + if settings("videoPreferredCodec") == "H265/HEVC": + if "hevc" in codecs: + codecs.remove("hevc") + codecs.insert(0, "hevc") # Add HEVC at the beginning if preferred if settings("transcode_mpeg2.bool"): codecs.remove("mpeg2video") diff --git a/tests/test_playutils_settings.py b/tests/test_playutils_settings.py new file mode 100644 index 000000000..fac4ebc64 --- /dev/null +++ b/tests/test_playutils_settings.py @@ -0,0 +1,303 @@ +from unittest.mock import patch + +import pytest + + +@pytest.fixture +def mock_play_utils(): + with patch('jellyfin_kodi.helper.playutils.PlayUtils') as MockPlayUtils: + mock_instance = MockPlayUtils.return_value + mock_instance.get_transcoding_video_codec.return_value = "" + yield mock_instance + + +def test_hevc_transcoding_scenario(mock_play_utils): + with patch('jellyfin_kodi.helper.playutils.settings') as mock_settings: + # Scenario 1: Force Transcode enabled, Transcode HEVC disabled + mock_settings.side_effect = [ + True, # transcode_h265 = True (Transcode HEVC disabled) + "", # videoPreferredCodec = "" (no preference) + False, # transcode_mpeg2 = False + False # transcode_vc1 = False + ] + mock_play_utils.get_transcoding_video_codec.return_value = "h264,mpeg4,mpeg2video,vc1" + result_1 = mock_play_utils.get_transcoding_video_codec() + + # Scenario 2: Force Transcode enabled, Transcode HEVC enabled + mock_settings.side_effect = [ + False, # transcode_h265 = False (Transcode HEVC enabled) + "", # videoPreferredCodec = "" (no preference) + False, # transcode_mpeg2 = False + False # transcode_vc1 = False + ] + mock_play_utils.get_transcoding_video_codec.return_value = "h264,mpeg4,mpeg2video,vc1,hevc" + result_2 = mock_play_utils.get_transcoding_video_codec() + + # Assertions + assert "hevc" not in result_1, "HEVC should not be in codec list when Transcode HEVC is disabled" + assert "hevc" in result_2, "HEVC should be in codec list when Transcode HEVC is enabled" + + # Ensure other codecs are present in both scenarios + for codec in ["h264", "mpeg4", "mpeg2video", "vc1"]: + assert codec in result_1, f"{codec} should be in codec list regardless of HEVC setting" + assert codec in result_2, f"{codec} should be in codec list regardless of HEVC setting" + + # Ensure the order is correct in both scenarios + assert result_1 == "h264,mpeg4,mpeg2video,vc1", "Codec order incorrect when HEVC is disabled" + assert result_2 == "h264,mpeg4,mpeg2video,vc1,hevc", "Codec order incorrect when HEVC is enabled" + + +@pytest.mark.parametrize("transcode_h265, preferred_codec, expected_result", [ + (False, "", "h264,mpeg4,mpeg2video,vc1,hevc"), + (True, "", "h264,mpeg4,mpeg2video,vc1"), + (False, "H265/HEVC", "hevc,h264,mpeg4,mpeg2video,vc1"), + (True, "H265/HEVC", "h264,mpeg4,mpeg2video,vc1"), + (False, "H264", "h264,mpeg4,mpeg2video,vc1,hevc"), + (True, "H264", "h264,mpeg4,mpeg2video,vc1"), + (False, "MPEG4", "mpeg4,h264,mpeg2video,vc1,hevc"), + (True, "MPEG4", "mpeg4,h264,mpeg2video,vc1"), +]) +def test_get_transcoding_video_codec_settings(mock_play_utils, transcode_h265, preferred_codec, expected_result): + with patch('jellyfin_kodi.helper.playutils.settings') as mock_settings: + mock_settings.side_effect = [transcode_h265, preferred_codec] + mock_play_utils.get_transcoding_video_codec.return_value = expected_result + result = mock_play_utils.get_transcoding_video_codec() + assert result == expected_result + + +@pytest.mark.parametrize("transcode_mpeg2, transcode_vc1, expected_result", [ + (False, False, "h264,mpeg4,mpeg2video,vc1,hevc"), + (True, False, "h264,mpeg4,vc1,hevc"), + (False, True, "h264,mpeg4,mpeg2video,hevc"), + (True, True, "h264,mpeg4,hevc"), +]) +def test_get_transcoding_video_codec_transcode_options(mock_play_utils, transcode_mpeg2, transcode_vc1, expected_result): + with patch('jellyfin_kodi.helper.playutils.settings') as mock_settings: + mock_settings.side_effect = [False, "", transcode_mpeg2, transcode_vc1] + mock_play_utils.get_transcoding_video_codec.return_value = expected_result + result = mock_play_utils.get_transcoding_video_codec() + assert result == expected_result + + +@pytest.mark.parametrize("preferred_codec, expected_first, expected_second", [ + ("H265/HEVC", "hevc", "h264"), + ("H264", "h264", "hevc"), + ("MPEG4", "mpeg4", "h264"), +]) +def test_get_transcoding_video_codec_order(mock_play_utils, preferred_codec, expected_first, expected_second): + with patch('jellyfin_kodi.helper.playutils.settings') as mock_settings: + mock_settings.side_effect = [False, preferred_codec] + mock_play_utils.get_transcoding_video_codec.return_value = f"{expected_first},{expected_second},mpeg2video,vc1" + result = mock_play_utils.get_transcoding_video_codec() + assert result.startswith(expected_first) + assert expected_second in result + assert result.index(expected_first) < result.index(expected_second) + + +def test_get_transcoding_video_codec_no_duplicates(mock_play_utils): + with patch('jellyfin_kodi.helper.playutils.settings') as mock_settings: + mock_settings.side_effect = [False, ""] + mock_play_utils.get_transcoding_video_codec.return_value = "h264,mpeg4,mpeg2video,vc1,hevc" + result = mock_play_utils.get_transcoding_video_codec() + assert result.count("hevc") == 1 + assert result.count("h264") == 1 + assert result.count("mpeg4") == 1 + assert result.count("mpeg2video") == 1 + assert result.count("vc1") == 1 + + +def test_get_transcoding_video_codec_empty_result(mock_play_utils): + with patch('jellyfin_kodi.helper.playutils.settings') as mock_settings: + mock_settings.side_effect = [True, ""] + mock_play_utils.get_transcoding_video_codec.return_value = "" + result = mock_play_utils.get_transcoding_video_codec() + assert result == "" + + +def test_get_transcoding_video_codec_single_codec(mock_play_utils): + with patch('jellyfin_kodi.helper.playutils.settings') as mock_settings: + mock_settings.side_effect = [True, "H264"] + mock_play_utils.get_transcoding_video_codec.return_value = "h264" + result = mock_play_utils.get_transcoding_video_codec() + assert result == "h264" + + +def test_get_transcoding_video_codec_unknown_preferred(mock_play_utils): + with patch('jellyfin_kodi.helper.playutils.settings') as mock_settings: + mock_settings.side_effect = [False, "UNKNOWN"] + mock_play_utils.get_transcoding_video_codec.return_value = "h264,mpeg4,mpeg2video,vc1,hevc" + result = mock_play_utils.get_transcoding_video_codec() + assert result == "h264,mpeg4,mpeg2video,vc1,hevc" + + +@pytest.mark.parametrize("transcode_h265, preferred_codec, transcode_mpeg2, transcode_vc1, expected_result", [ + (True, "H264", True, True, "h264,mpeg4"), + (False, "H265/HEVC", False, False, "hevc,h264,mpeg4,mpeg2video,vc1"), + (True, "MPEG4", True, False, "mpeg4,h264,vc1"), +]) +def test_get_transcoding_video_codec_combined_settings(mock_play_utils, transcode_h265, preferred_codec, transcode_mpeg2, transcode_vc1, expected_result): + with patch('jellyfin_kodi.helper.playutils.settings') as mock_settings: + mock_settings.side_effect = [transcode_h265, preferred_codec, transcode_mpeg2, transcode_vc1] + mock_play_utils.get_transcoding_video_codec.return_value = expected_result + result = mock_play_utils.get_transcoding_video_codec() + assert result == expected_result + + +@pytest.mark.parametrize("transcode_h265, preferred_codec, expected_result", [ + (False, "", "h264,mpeg4,mpeg2video,vc1,hevc"), + (True, "", "h264,mpeg4,mpeg2video,vc1"), + (False, "H265/HEVC", "hevc,h264,mpeg4,mpeg2video,vc1"), + (True, "H265/HEVC", "h264,mpeg4,mpeg2video,vc1"), + (False, "H264", "h264,mpeg4,mpeg2video,vc1,hevc"), + (True, "H264", "h264,mpeg4,mpeg2video,vc1"), + (False, "MPEG4", "mpeg4,h264,mpeg2video,vc1,hevc"), + (True, "MPEG4", "mpeg4,h264,mpeg2video,vc1"), +]) +def test_get_directplay_video_codec(mock_play_utils, transcode_h265, preferred_codec, expected_result): + with patch('jellyfin_kodi.helper.playutils.settings') as mock_settings: + mock_settings.side_effect = [transcode_h265, preferred_codec] + mock_play_utils.get_directplay_video_codec.return_value = expected_result + result = mock_play_utils.get_directplay_video_codec() + assert result == expected_result + + +@pytest.mark.parametrize("transcode_mpeg2, transcode_vc1, expected_result", [ + (False, False, "h264,mpeg4,mpeg2video,vc1,hevc"), + (True, False, "h264,mpeg4,vc1,hevc"), + (False, True, "h264,mpeg4,mpeg2video,hevc"), + (True, True, "h264,mpeg4,hevc"), +]) +def test_get_directplay_video_codec_transcode_options(mock_play_utils, transcode_mpeg2, transcode_vc1, expected_result): + with patch('jellyfin_kodi.helper.playutils.settings') as mock_settings: + mock_settings.side_effect = [False, "", transcode_mpeg2, transcode_vc1] + mock_play_utils.get_directplay_video_codec.return_value = expected_result + result = mock_play_utils.get_directplay_video_codec() + assert result == expected_result + + +def test_get_directplay_video_codec_no_duplicates(mock_play_utils): + with patch('jellyfin_kodi.helper.playutils.settings') as mock_settings: + mock_settings.side_effect = [False, ""] + mock_play_utils.get_directplay_video_codec.return_value = "h264,mpeg4,mpeg2video,vc1,hevc" + result = mock_play_utils.get_directplay_video_codec() + assert result.count("hevc") == 1 + assert result.count("h264") == 1 + assert result.count("mpeg4") == 1 + assert result.count("mpeg2video") == 1 + assert result.count("vc1") == 1 + + +def test_get_directplay_video_codec_empty_result(mock_play_utils): + with patch('jellyfin_kodi.helper.playutils.settings') as mock_settings: + mock_settings.side_effect = [True, ""] + mock_play_utils.get_directplay_video_codec.return_value = "" + result = mock_play_utils.get_directplay_video_codec() + assert result == "" + + +def test_get_directplay_video_codec_single_codec(mock_play_utils): + with patch('jellyfin_kodi.helper.playutils.settings') as mock_settings: + mock_settings.side_effect = [True, "H264"] + mock_play_utils.get_directplay_video_codec.return_value = "h264" + result = mock_play_utils.get_directplay_video_codec() + assert result == "h264" + + +def test_get_directplay_video_codec_unknown_preferred(mock_play_utils): + with patch('jellyfin_kodi.helper.playutils.settings') as mock_settings: + mock_settings.side_effect = [False, "UNKNOWN"] + mock_play_utils.get_directplay_video_codec.return_value = "h264,mpeg4,mpeg2video,vc1,hevc" + result = mock_play_utils.get_directplay_video_codec() + assert result == "h264,mpeg4,mpeg2video,vc1,hevc" + + +@pytest.mark.parametrize("transcode_h265, preferred_codec, transcode_mpeg2, transcode_vc1, expected_result", [ + (True, "H264", True, True, "h264,mpeg4"), + (False, "H265/HEVC", False, False, "hevc,h264,mpeg4,mpeg2video,vc1"), + (True, "MPEG4", True, False, "mpeg4,h264,vc1"), +]) +def test_get_directplay_video_codec_combined_settings(mock_play_utils, transcode_h265, preferred_codec, transcode_mpeg2, transcode_vc1, expected_result): + with patch('jellyfin_kodi.helper.playutils.settings') as mock_settings: + mock_settings.side_effect = [transcode_h265, preferred_codec, transcode_mpeg2, transcode_vc1] + mock_play_utils.get_directplay_video_codec.return_value = expected_result + result = mock_play_utils.get_directplay_video_codec() + assert result == expected_result + + +@pytest.mark.parametrize("preferred_codec, expected_result", [ + ("", "aac,mp3,ac3,opus,flac,vorbis"), + ("AAC", "aac,mp3,ac3,opus,flac,vorbis"), + ("MP3", "mp3,aac,ac3,opus,flac,vorbis"), + ("AC3", "ac3,aac,mp3,opus,flac,vorbis"), + ("OPUS", "opus,aac,mp3,ac3,flac,vorbis"), + ("FLAC", "flac,aac,mp3,ac3,opus,vorbis"), + ("VORBIS", "vorbis,aac,mp3,ac3,opus,flac"), + ("UNKNOWN", "aac,mp3,ac3,opus,flac,vorbis"), +]) +def test_get_transcoding_audio_codec(mock_play_utils, preferred_codec, expected_result): + with patch('jellyfin_kodi.helper.playutils.settings') as mock_settings: + mock_settings.return_value = preferred_codec + mock_play_utils.get_transcoding_audio_codec.return_value = expected_result + result = mock_play_utils.get_transcoding_audio_codec() + assert result == expected_result + + +def test_get_transcoding_audio_codec_case_insensitive(mock_play_utils): + with patch('jellyfin_kodi.helper.playutils.settings') as mock_settings: + mock_settings.return_value = "aAc" + mock_play_utils.get_transcoding_audio_codec.return_value = "aac,mp3,ac3,opus,flac,vorbis" + result = mock_play_utils.get_transcoding_audio_codec() + assert result == "aac,mp3,ac3,opus,flac,vorbis" + + +def test_get_transcoding_audio_codec_no_duplicates(mock_play_utils): + with patch('jellyfin_kodi.helper.playutils.settings') as mock_settings: + mock_settings.return_value = "" + mock_play_utils.get_transcoding_audio_codec.return_value = "aac,mp3,ac3,opus,flac,vorbis" + result = mock_play_utils.get_transcoding_audio_codec() + assert result.count("aac") == 1 + assert result.count("mp3") == 1 + assert result.count("ac3") == 1 + assert result.count("opus") == 1 + assert result.count("flac") == 1 + assert result.count("vorbis") == 1 + + +def test_get_transcoding_audio_codec_empty_result(mock_play_utils): + with patch('jellyfin_kodi.helper.playutils.settings') as mock_settings: + mock_settings.return_value = "" + mock_play_utils.get_transcoding_audio_codec.return_value = "" + result = mock_play_utils.get_transcoding_audio_codec() + assert result == "" + + +def test_get_transcoding_audio_codec_single_codec(mock_play_utils): + with patch('jellyfin_kodi.helper.playutils.settings') as mock_settings: + mock_settings.return_value = "AAC" + mock_play_utils.get_transcoding_audio_codec.return_value = "aac" + result = mock_play_utils.get_transcoding_audio_codec() + assert result == "aac" + + +def test_get_transcoding_audio_codec_preserve_order(mock_play_utils): + with patch('jellyfin_kodi.helper.playutils.settings') as mock_settings: + mock_settings.return_value = "" + mock_play_utils.get_transcoding_audio_codec.return_value = "aac,mp3,ac3,opus,flac,vorbis" + result = mock_play_utils.get_transcoding_audio_codec() + assert result == "aac,mp3,ac3,opus,flac,vorbis" + + +def test_get_transcoding_audio_codec_multiple_calls(mock_play_utils): + with patch('jellyfin_kodi.helper.playutils.settings') as mock_settings: + mock_settings.side_effect = ["AAC", "MP3", "FLAC"] + mock_play_utils.get_transcoding_audio_codec.side_effect = [ + "aac,mp3,ac3,opus,flac,vorbis", + "mp3,aac,ac3,opus,flac,vorbis", + "flac,aac,mp3,ac3,opus,vorbis" + ] + result1 = mock_play_utils.get_transcoding_audio_codec() + result2 = mock_play_utils.get_transcoding_audio_codec() + result3 = mock_play_utils.get_transcoding_audio_codec() + assert result1 == "aac,mp3,ac3,opus,flac,vorbis" + assert result2 == "mp3,aac,ac3,opus,flac,vorbis" + assert result3 == "flac,aac,mp3,ac3,opus,vorbis" From 6cde7a1141a78f815ef1a6c622c4efe0e80509f5 Mon Sep 17 00:00:00 2001 From: plodri <132933267+plodri@users.noreply.github.com> Date: Wed, 24 Jul 2024 17:34:45 +0000 Subject: [PATCH 2/4] fix linting --- tests/test_playutils_settings.py | 318 ++++++++++++++++++++----------- 1 file changed, 204 insertions(+), 114 deletions(-) diff --git a/tests/test_playutils_settings.py b/tests/test_playutils_settings.py index fac4ebc64..b75d7341a 100644 --- a/tests/test_playutils_settings.py +++ b/tests/test_playutils_settings.py @@ -5,89 +5,122 @@ @pytest.fixture def mock_play_utils(): - with patch('jellyfin_kodi.helper.playutils.PlayUtils') as MockPlayUtils: + with patch("jellyfin_kodi.helper.playutils.PlayUtils") as MockPlayUtils: mock_instance = MockPlayUtils.return_value mock_instance.get_transcoding_video_codec.return_value = "" yield mock_instance def test_hevc_transcoding_scenario(mock_play_utils): - with patch('jellyfin_kodi.helper.playutils.settings') as mock_settings: + with patch("jellyfin_kodi.helper.playutils.settings") as mock_settings: # Scenario 1: Force Transcode enabled, Transcode HEVC disabled mock_settings.side_effect = [ - True, # transcode_h265 = True (Transcode HEVC disabled) - "", # videoPreferredCodec = "" (no preference) + True, # transcode_h265 = True (Transcode HEVC disabled) + "", # videoPreferredCodec = "" (no preference) False, # transcode_mpeg2 = False - False # transcode_vc1 = False + False, # transcode_vc1 = False ] - mock_play_utils.get_transcoding_video_codec.return_value = "h264,mpeg4,mpeg2video,vc1" + mock_play_utils.get_transcoding_video_codec.return_value = ( + "h264,mpeg4,mpeg2video,vc1" + ) result_1 = mock_play_utils.get_transcoding_video_codec() # Scenario 2: Force Transcode enabled, Transcode HEVC enabled mock_settings.side_effect = [ False, # transcode_h265 = False (Transcode HEVC enabled) - "", # videoPreferredCodec = "" (no preference) + "", # videoPreferredCodec = "" (no preference) False, # transcode_mpeg2 = False - False # transcode_vc1 = False + False, # transcode_vc1 = False ] - mock_play_utils.get_transcoding_video_codec.return_value = "h264,mpeg4,mpeg2video,vc1,hevc" + mock_play_utils.get_transcoding_video_codec.return_value = ( + "h264,mpeg4,mpeg2video,vc1,hevc" + ) result_2 = mock_play_utils.get_transcoding_video_codec() # Assertions - assert "hevc" not in result_1, "HEVC should not be in codec list when Transcode HEVC is disabled" - assert "hevc" in result_2, "HEVC should be in codec list when Transcode HEVC is enabled" + assert ( + "hevc" not in result_1 + ), "HEVC should not be in codec list when Transcode HEVC is disabled" + assert ( + "hevc" in result_2 + ), "HEVC should be in codec list when Transcode HEVC is enabled" # Ensure other codecs are present in both scenarios for codec in ["h264", "mpeg4", "mpeg2video", "vc1"]: - assert codec in result_1, f"{codec} should be in codec list regardless of HEVC setting" - assert codec in result_2, f"{codec} should be in codec list regardless of HEVC setting" + assert ( + codec in result_1 + ), f"{codec} should be in codec list regardless of HEVC setting" + assert ( + codec in result_2 + ), f"{codec} should be in codec list regardless of HEVC setting" # Ensure the order is correct in both scenarios - assert result_1 == "h264,mpeg4,mpeg2video,vc1", "Codec order incorrect when HEVC is disabled" - assert result_2 == "h264,mpeg4,mpeg2video,vc1,hevc", "Codec order incorrect when HEVC is enabled" - - -@pytest.mark.parametrize("transcode_h265, preferred_codec, expected_result", [ - (False, "", "h264,mpeg4,mpeg2video,vc1,hevc"), - (True, "", "h264,mpeg4,mpeg2video,vc1"), - (False, "H265/HEVC", "hevc,h264,mpeg4,mpeg2video,vc1"), - (True, "H265/HEVC", "h264,mpeg4,mpeg2video,vc1"), - (False, "H264", "h264,mpeg4,mpeg2video,vc1,hevc"), - (True, "H264", "h264,mpeg4,mpeg2video,vc1"), - (False, "MPEG4", "mpeg4,h264,mpeg2video,vc1,hevc"), - (True, "MPEG4", "mpeg4,h264,mpeg2video,vc1"), -]) -def test_get_transcoding_video_codec_settings(mock_play_utils, transcode_h265, preferred_codec, expected_result): - with patch('jellyfin_kodi.helper.playutils.settings') as mock_settings: + assert ( + result_1 == "h264,mpeg4,mpeg2video,vc1" + ), "Codec order incorrect when HEVC is disabled" + assert ( + result_2 == "h264,mpeg4,mpeg2video,vc1,hevc" + ), "Codec order incorrect when HEVC is enabled" + + +@pytest.mark.parametrize( + "transcode_h265, preferred_codec, expected_result", + [ + (False, "", "h264,mpeg4,mpeg2video,vc1,hevc"), + (True, "", "h264,mpeg4,mpeg2video,vc1"), + (False, "H265/HEVC", "hevc,h264,mpeg4,mpeg2video,vc1"), + (True, "H265/HEVC", "h264,mpeg4,mpeg2video,vc1"), + (False, "H264", "h264,mpeg4,mpeg2video,vc1,hevc"), + (True, "H264", "h264,mpeg4,mpeg2video,vc1"), + (False, "MPEG4", "mpeg4,h264,mpeg2video,vc1,hevc"), + (True, "MPEG4", "mpeg4,h264,mpeg2video,vc1"), + ], +) +def test_get_transcoding_video_codec_settings( + mock_play_utils, transcode_h265, preferred_codec, expected_result +): + with patch("jellyfin_kodi.helper.playutils.settings") as mock_settings: mock_settings.side_effect = [transcode_h265, preferred_codec] mock_play_utils.get_transcoding_video_codec.return_value = expected_result result = mock_play_utils.get_transcoding_video_codec() assert result == expected_result -@pytest.mark.parametrize("transcode_mpeg2, transcode_vc1, expected_result", [ - (False, False, "h264,mpeg4,mpeg2video,vc1,hevc"), - (True, False, "h264,mpeg4,vc1,hevc"), - (False, True, "h264,mpeg4,mpeg2video,hevc"), - (True, True, "h264,mpeg4,hevc"), -]) -def test_get_transcoding_video_codec_transcode_options(mock_play_utils, transcode_mpeg2, transcode_vc1, expected_result): - with patch('jellyfin_kodi.helper.playutils.settings') as mock_settings: +@pytest.mark.parametrize( + "transcode_mpeg2, transcode_vc1, expected_result", + [ + (False, False, "h264,mpeg4,mpeg2video,vc1,hevc"), + (True, False, "h264,mpeg4,vc1,hevc"), + (False, True, "h264,mpeg4,mpeg2video,hevc"), + (True, True, "h264,mpeg4,hevc"), + ], +) +def test_get_transcoding_video_codec_transcode_options( + mock_play_utils, transcode_mpeg2, transcode_vc1, expected_result +): + with patch("jellyfin_kodi.helper.playutils.settings") as mock_settings: mock_settings.side_effect = [False, "", transcode_mpeg2, transcode_vc1] mock_play_utils.get_transcoding_video_codec.return_value = expected_result result = mock_play_utils.get_transcoding_video_codec() assert result == expected_result -@pytest.mark.parametrize("preferred_codec, expected_first, expected_second", [ - ("H265/HEVC", "hevc", "h264"), - ("H264", "h264", "hevc"), - ("MPEG4", "mpeg4", "h264"), -]) -def test_get_transcoding_video_codec_order(mock_play_utils, preferred_codec, expected_first, expected_second): - with patch('jellyfin_kodi.helper.playutils.settings') as mock_settings: +@pytest.mark.parametrize( + "preferred_codec, expected_first, expected_second", + [ + ("H265/HEVC", "hevc", "h264"), + ("H264", "h264", "hevc"), + ("MPEG4", "mpeg4", "h264"), + ], +) +def test_get_transcoding_video_codec_order( + mock_play_utils, preferred_codec, expected_first, expected_second +): + with patch("jellyfin_kodi.helper.playutils.settings") as mock_settings: mock_settings.side_effect = [False, preferred_codec] - mock_play_utils.get_transcoding_video_codec.return_value = f"{expected_first},{expected_second},mpeg2video,vc1" + mock_play_utils.get_transcoding_video_codec.return_value = ( + f"{expected_first},{expected_second},mpeg2video,vc1" + ) result = mock_play_utils.get_transcoding_video_codec() assert result.startswith(expected_first) assert expected_second in result @@ -95,9 +128,11 @@ def test_get_transcoding_video_codec_order(mock_play_utils, preferred_codec, exp def test_get_transcoding_video_codec_no_duplicates(mock_play_utils): - with patch('jellyfin_kodi.helper.playutils.settings') as mock_settings: + with patch("jellyfin_kodi.helper.playutils.settings") as mock_settings: mock_settings.side_effect = [False, ""] - mock_play_utils.get_transcoding_video_codec.return_value = "h264,mpeg4,mpeg2video,vc1,hevc" + mock_play_utils.get_transcoding_video_codec.return_value = ( + "h264,mpeg4,mpeg2video,vc1,hevc" + ) result = mock_play_utils.get_transcoding_video_codec() assert result.count("hevc") == 1 assert result.count("h264") == 1 @@ -107,7 +142,7 @@ def test_get_transcoding_video_codec_no_duplicates(mock_play_utils): def test_get_transcoding_video_codec_empty_result(mock_play_utils): - with patch('jellyfin_kodi.helper.playutils.settings') as mock_settings: + with patch("jellyfin_kodi.helper.playutils.settings") as mock_settings: mock_settings.side_effect = [True, ""] mock_play_utils.get_transcoding_video_codec.return_value = "" result = mock_play_utils.get_transcoding_video_codec() @@ -115,7 +150,7 @@ def test_get_transcoding_video_codec_empty_result(mock_play_utils): def test_get_transcoding_video_codec_single_codec(mock_play_utils): - with patch('jellyfin_kodi.helper.playutils.settings') as mock_settings: + with patch("jellyfin_kodi.helper.playutils.settings") as mock_settings: mock_settings.side_effect = [True, "H264"] mock_play_utils.get_transcoding_video_codec.return_value = "h264" result = mock_play_utils.get_transcoding_video_codec() @@ -123,52 +158,79 @@ def test_get_transcoding_video_codec_single_codec(mock_play_utils): def test_get_transcoding_video_codec_unknown_preferred(mock_play_utils): - with patch('jellyfin_kodi.helper.playutils.settings') as mock_settings: + with patch("jellyfin_kodi.helper.playutils.settings") as mock_settings: mock_settings.side_effect = [False, "UNKNOWN"] - mock_play_utils.get_transcoding_video_codec.return_value = "h264,mpeg4,mpeg2video,vc1,hevc" + mock_play_utils.get_transcoding_video_codec.return_value = ( + "h264,mpeg4,mpeg2video,vc1,hevc" + ) result = mock_play_utils.get_transcoding_video_codec() assert result == "h264,mpeg4,mpeg2video,vc1,hevc" -@pytest.mark.parametrize("transcode_h265, preferred_codec, transcode_mpeg2, transcode_vc1, expected_result", [ - (True, "H264", True, True, "h264,mpeg4"), - (False, "H265/HEVC", False, False, "hevc,h264,mpeg4,mpeg2video,vc1"), - (True, "MPEG4", True, False, "mpeg4,h264,vc1"), -]) -def test_get_transcoding_video_codec_combined_settings(mock_play_utils, transcode_h265, preferred_codec, transcode_mpeg2, transcode_vc1, expected_result): - with patch('jellyfin_kodi.helper.playutils.settings') as mock_settings: - mock_settings.side_effect = [transcode_h265, preferred_codec, transcode_mpeg2, transcode_vc1] +@pytest.mark.parametrize( + "transcode_h265, preferred_codec, transcode_mpeg2, transcode_vc1, expected_result", + [ + (True, "H264", True, True, "h264,mpeg4"), + (False, "H265/HEVC", False, False, "hevc,h264,mpeg4,mpeg2video,vc1"), + (True, "MPEG4", True, False, "mpeg4,h264,vc1"), + ], +) +def test_get_transcoding_video_codec_combined_settings( + mock_play_utils, + transcode_h265, + preferred_codec, + transcode_mpeg2, + transcode_vc1, + expected_result, +): + with patch("jellyfin_kodi.helper.playutils.settings") as mock_settings: + mock_settings.side_effect = [ + transcode_h265, + preferred_codec, + transcode_mpeg2, + transcode_vc1, + ] mock_play_utils.get_transcoding_video_codec.return_value = expected_result result = mock_play_utils.get_transcoding_video_codec() assert result == expected_result -@pytest.mark.parametrize("transcode_h265, preferred_codec, expected_result", [ - (False, "", "h264,mpeg4,mpeg2video,vc1,hevc"), - (True, "", "h264,mpeg4,mpeg2video,vc1"), - (False, "H265/HEVC", "hevc,h264,mpeg4,mpeg2video,vc1"), - (True, "H265/HEVC", "h264,mpeg4,mpeg2video,vc1"), - (False, "H264", "h264,mpeg4,mpeg2video,vc1,hevc"), - (True, "H264", "h264,mpeg4,mpeg2video,vc1"), - (False, "MPEG4", "mpeg4,h264,mpeg2video,vc1,hevc"), - (True, "MPEG4", "mpeg4,h264,mpeg2video,vc1"), -]) -def test_get_directplay_video_codec(mock_play_utils, transcode_h265, preferred_codec, expected_result): - with patch('jellyfin_kodi.helper.playutils.settings') as mock_settings: +@pytest.mark.parametrize( + "transcode_h265, preferred_codec, expected_result", + [ + (False, "", "h264,mpeg4,mpeg2video,vc1,hevc"), + (True, "", "h264,mpeg4,mpeg2video,vc1"), + (False, "H265/HEVC", "hevc,h264,mpeg4,mpeg2video,vc1"), + (True, "H265/HEVC", "h264,mpeg4,mpeg2video,vc1"), + (False, "H264", "h264,mpeg4,mpeg2video,vc1,hevc"), + (True, "H264", "h264,mpeg4,mpeg2video,vc1"), + (False, "MPEG4", "mpeg4,h264,mpeg2video,vc1,hevc"), + (True, "MPEG4", "mpeg4,h264,mpeg2video,vc1"), + ], +) +def test_get_directplay_video_codec( + mock_play_utils, transcode_h265, preferred_codec, expected_result +): + with patch("jellyfin_kodi.helper.playutils.settings") as mock_settings: mock_settings.side_effect = [transcode_h265, preferred_codec] mock_play_utils.get_directplay_video_codec.return_value = expected_result result = mock_play_utils.get_directplay_video_codec() assert result == expected_result -@pytest.mark.parametrize("transcode_mpeg2, transcode_vc1, expected_result", [ - (False, False, "h264,mpeg4,mpeg2video,vc1,hevc"), - (True, False, "h264,mpeg4,vc1,hevc"), - (False, True, "h264,mpeg4,mpeg2video,hevc"), - (True, True, "h264,mpeg4,hevc"), -]) -def test_get_directplay_video_codec_transcode_options(mock_play_utils, transcode_mpeg2, transcode_vc1, expected_result): - with patch('jellyfin_kodi.helper.playutils.settings') as mock_settings: +@pytest.mark.parametrize( + "transcode_mpeg2, transcode_vc1, expected_result", + [ + (False, False, "h264,mpeg4,mpeg2video,vc1,hevc"), + (True, False, "h264,mpeg4,vc1,hevc"), + (False, True, "h264,mpeg4,mpeg2video,hevc"), + (True, True, "h264,mpeg4,hevc"), + ], +) +def test_get_directplay_video_codec_transcode_options( + mock_play_utils, transcode_mpeg2, transcode_vc1, expected_result +): + with patch("jellyfin_kodi.helper.playutils.settings") as mock_settings: mock_settings.side_effect = [False, "", transcode_mpeg2, transcode_vc1] mock_play_utils.get_directplay_video_codec.return_value = expected_result result = mock_play_utils.get_directplay_video_codec() @@ -176,9 +238,11 @@ def test_get_directplay_video_codec_transcode_options(mock_play_utils, transcode def test_get_directplay_video_codec_no_duplicates(mock_play_utils): - with patch('jellyfin_kodi.helper.playutils.settings') as mock_settings: + with patch("jellyfin_kodi.helper.playutils.settings") as mock_settings: mock_settings.side_effect = [False, ""] - mock_play_utils.get_directplay_video_codec.return_value = "h264,mpeg4,mpeg2video,vc1,hevc" + mock_play_utils.get_directplay_video_codec.return_value = ( + "h264,mpeg4,mpeg2video,vc1,hevc" + ) result = mock_play_utils.get_directplay_video_codec() assert result.count("hevc") == 1 assert result.count("h264") == 1 @@ -188,7 +252,7 @@ def test_get_directplay_video_codec_no_duplicates(mock_play_utils): def test_get_directplay_video_codec_empty_result(mock_play_utils): - with patch('jellyfin_kodi.helper.playutils.settings') as mock_settings: + with patch("jellyfin_kodi.helper.playutils.settings") as mock_settings: mock_settings.side_effect = [True, ""] mock_play_utils.get_directplay_video_codec.return_value = "" result = mock_play_utils.get_directplay_video_codec() @@ -196,7 +260,7 @@ def test_get_directplay_video_codec_empty_result(mock_play_utils): def test_get_directplay_video_codec_single_codec(mock_play_utils): - with patch('jellyfin_kodi.helper.playutils.settings') as mock_settings: + with patch("jellyfin_kodi.helper.playutils.settings") as mock_settings: mock_settings.side_effect = [True, "H264"] mock_play_utils.get_directplay_video_codec.return_value = "h264" result = mock_play_utils.get_directplay_video_codec() @@ -204,38 +268,58 @@ def test_get_directplay_video_codec_single_codec(mock_play_utils): def test_get_directplay_video_codec_unknown_preferred(mock_play_utils): - with patch('jellyfin_kodi.helper.playutils.settings') as mock_settings: + with patch("jellyfin_kodi.helper.playutils.settings") as mock_settings: mock_settings.side_effect = [False, "UNKNOWN"] - mock_play_utils.get_directplay_video_codec.return_value = "h264,mpeg4,mpeg2video,vc1,hevc" + mock_play_utils.get_directplay_video_codec.return_value = ( + "h264,mpeg4,mpeg2video,vc1,hevc" + ) result = mock_play_utils.get_directplay_video_codec() assert result == "h264,mpeg4,mpeg2video,vc1,hevc" -@pytest.mark.parametrize("transcode_h265, preferred_codec, transcode_mpeg2, transcode_vc1, expected_result", [ - (True, "H264", True, True, "h264,mpeg4"), - (False, "H265/HEVC", False, False, "hevc,h264,mpeg4,mpeg2video,vc1"), - (True, "MPEG4", True, False, "mpeg4,h264,vc1"), -]) -def test_get_directplay_video_codec_combined_settings(mock_play_utils, transcode_h265, preferred_codec, transcode_mpeg2, transcode_vc1, expected_result): - with patch('jellyfin_kodi.helper.playutils.settings') as mock_settings: - mock_settings.side_effect = [transcode_h265, preferred_codec, transcode_mpeg2, transcode_vc1] +@pytest.mark.parametrize( + "transcode_h265, preferred_codec, transcode_mpeg2, transcode_vc1, expected_result", + [ + (True, "H264", True, True, "h264,mpeg4"), + (False, "H265/HEVC", False, False, "hevc,h264,mpeg4,mpeg2video,vc1"), + (True, "MPEG4", True, False, "mpeg4,h264,vc1"), + ], +) +def test_get_directplay_video_codec_combined_settings( + mock_play_utils, + transcode_h265, + preferred_codec, + transcode_mpeg2, + transcode_vc1, + expected_result, +): + with patch("jellyfin_kodi.helper.playutils.settings") as mock_settings: + mock_settings.side_effect = [ + transcode_h265, + preferred_codec, + transcode_mpeg2, + transcode_vc1, + ] mock_play_utils.get_directplay_video_codec.return_value = expected_result result = mock_play_utils.get_directplay_video_codec() assert result == expected_result -@pytest.mark.parametrize("preferred_codec, expected_result", [ - ("", "aac,mp3,ac3,opus,flac,vorbis"), - ("AAC", "aac,mp3,ac3,opus,flac,vorbis"), - ("MP3", "mp3,aac,ac3,opus,flac,vorbis"), - ("AC3", "ac3,aac,mp3,opus,flac,vorbis"), - ("OPUS", "opus,aac,mp3,ac3,flac,vorbis"), - ("FLAC", "flac,aac,mp3,ac3,opus,vorbis"), - ("VORBIS", "vorbis,aac,mp3,ac3,opus,flac"), - ("UNKNOWN", "aac,mp3,ac3,opus,flac,vorbis"), -]) +@pytest.mark.parametrize( + "preferred_codec, expected_result", + [ + ("", "aac,mp3,ac3,opus,flac,vorbis"), + ("AAC", "aac,mp3,ac3,opus,flac,vorbis"), + ("MP3", "mp3,aac,ac3,opus,flac,vorbis"), + ("AC3", "ac3,aac,mp3,opus,flac,vorbis"), + ("OPUS", "opus,aac,mp3,ac3,flac,vorbis"), + ("FLAC", "flac,aac,mp3,ac3,opus,vorbis"), + ("VORBIS", "vorbis,aac,mp3,ac3,opus,flac"), + ("UNKNOWN", "aac,mp3,ac3,opus,flac,vorbis"), + ], +) def test_get_transcoding_audio_codec(mock_play_utils, preferred_codec, expected_result): - with patch('jellyfin_kodi.helper.playutils.settings') as mock_settings: + with patch("jellyfin_kodi.helper.playutils.settings") as mock_settings: mock_settings.return_value = preferred_codec mock_play_utils.get_transcoding_audio_codec.return_value = expected_result result = mock_play_utils.get_transcoding_audio_codec() @@ -243,17 +327,21 @@ def test_get_transcoding_audio_codec(mock_play_utils, preferred_codec, expected_ def test_get_transcoding_audio_codec_case_insensitive(mock_play_utils): - with patch('jellyfin_kodi.helper.playutils.settings') as mock_settings: + with patch("jellyfin_kodi.helper.playutils.settings") as mock_settings: mock_settings.return_value = "aAc" - mock_play_utils.get_transcoding_audio_codec.return_value = "aac,mp3,ac3,opus,flac,vorbis" + mock_play_utils.get_transcoding_audio_codec.return_value = ( + "aac,mp3,ac3,opus,flac,vorbis" + ) result = mock_play_utils.get_transcoding_audio_codec() assert result == "aac,mp3,ac3,opus,flac,vorbis" def test_get_transcoding_audio_codec_no_duplicates(mock_play_utils): - with patch('jellyfin_kodi.helper.playutils.settings') as mock_settings: + with patch("jellyfin_kodi.helper.playutils.settings") as mock_settings: mock_settings.return_value = "" - mock_play_utils.get_transcoding_audio_codec.return_value = "aac,mp3,ac3,opus,flac,vorbis" + mock_play_utils.get_transcoding_audio_codec.return_value = ( + "aac,mp3,ac3,opus,flac,vorbis" + ) result = mock_play_utils.get_transcoding_audio_codec() assert result.count("aac") == 1 assert result.count("mp3") == 1 @@ -264,7 +352,7 @@ def test_get_transcoding_audio_codec_no_duplicates(mock_play_utils): def test_get_transcoding_audio_codec_empty_result(mock_play_utils): - with patch('jellyfin_kodi.helper.playutils.settings') as mock_settings: + with patch("jellyfin_kodi.helper.playutils.settings") as mock_settings: mock_settings.return_value = "" mock_play_utils.get_transcoding_audio_codec.return_value = "" result = mock_play_utils.get_transcoding_audio_codec() @@ -272,7 +360,7 @@ def test_get_transcoding_audio_codec_empty_result(mock_play_utils): def test_get_transcoding_audio_codec_single_codec(mock_play_utils): - with patch('jellyfin_kodi.helper.playutils.settings') as mock_settings: + with patch("jellyfin_kodi.helper.playutils.settings") as mock_settings: mock_settings.return_value = "AAC" mock_play_utils.get_transcoding_audio_codec.return_value = "aac" result = mock_play_utils.get_transcoding_audio_codec() @@ -280,20 +368,22 @@ def test_get_transcoding_audio_codec_single_codec(mock_play_utils): def test_get_transcoding_audio_codec_preserve_order(mock_play_utils): - with patch('jellyfin_kodi.helper.playutils.settings') as mock_settings: + with patch("jellyfin_kodi.helper.playutils.settings") as mock_settings: mock_settings.return_value = "" - mock_play_utils.get_transcoding_audio_codec.return_value = "aac,mp3,ac3,opus,flac,vorbis" + mock_play_utils.get_transcoding_audio_codec.return_value = ( + "aac,mp3,ac3,opus,flac,vorbis" + ) result = mock_play_utils.get_transcoding_audio_codec() assert result == "aac,mp3,ac3,opus,flac,vorbis" def test_get_transcoding_audio_codec_multiple_calls(mock_play_utils): - with patch('jellyfin_kodi.helper.playutils.settings') as mock_settings: + with patch("jellyfin_kodi.helper.playutils.settings") as mock_settings: mock_settings.side_effect = ["AAC", "MP3", "FLAC"] mock_play_utils.get_transcoding_audio_codec.side_effect = [ "aac,mp3,ac3,opus,flac,vorbis", "mp3,aac,ac3,opus,flac,vorbis", - "flac,aac,mp3,ac3,opus,vorbis" + "flac,aac,mp3,ac3,opus,vorbis", ] result1 = mock_play_utils.get_transcoding_audio_codec() result2 = mock_play_utils.get_transcoding_audio_codec() From d258f0d14c15cae4e4acfcad30b85a0c034c280b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Odd=20Str=C3=A5b=C3=B8?= Date: Fri, 9 Aug 2024 18:24:38 +0000 Subject: [PATCH 3/4] Mock dependencies instead of the function --- jellyfin_kodi/helper/playutils.py | 7 +- tests/test_playutils_settings.py | 459 ++++++++++-------------------- 2 files changed, 159 insertions(+), 307 deletions(-) diff --git a/jellyfin_kodi/helper/playutils.py b/jellyfin_kodi/helper/playutils.py index d25f31caa..b17acb268 100644 --- a/jellyfin_kodi/helper/playutils.py +++ b/jellyfin_kodi/helper/playutils.py @@ -363,11 +363,10 @@ def get_resolution(self): ) def get_directplay_video_codec(self): - codecs = ["h264", "hevc", "h265", "mpeg4", "mpeg2video", "vc1", "vp9", "av1"] + codecs = ["h264", "hevc", "mpeg4", "mpeg2video", "vc1", "vp9", "av1"] if settings("transcode_h265.bool"): codecs.remove("hevc") - codecs.remove("h265") if settings("transcode_mpeg2.bool"): codecs.remove("mpeg2video") @@ -387,7 +386,7 @@ def get_transcoding_video_codec(self): codecs = ["h264", "mpeg4", "mpeg2video", "vc1"] if not settings("transcode_h265.bool"): - codecs.append("hevc") # Add HEVC if transcoding is not forced + codecs.insert(1, "hevc") # Add HEVC if transcoding is not forced if settings("videoPreferredCodec") == "H265/HEVC": if "hevc" in codecs: @@ -481,7 +480,7 @@ def get_device_profile(self): profile["CodecProfiles"].append( { "Type": "Video", - "codec": "h265,hevc", + "codec": "hevc", "Conditions": [ { "Condition": "EqualsAny", diff --git a/tests/test_playutils_settings.py b/tests/test_playutils_settings.py index b75d7341a..9cdcfa5d7 100644 --- a/tests/test_playutils_settings.py +++ b/tests/test_playutils_settings.py @@ -1,308 +1,213 @@ -from unittest.mock import patch - import pytest +from jellyfin_kodi.helper import playutils +from jellyfin_kodi.helper.playutils import PlayUtils + @pytest.fixture -def mock_play_utils(): - with patch("jellyfin_kodi.helper.playutils.PlayUtils") as MockPlayUtils: - mock_instance = MockPlayUtils.return_value - mock_instance.get_transcoding_video_codec.return_value = "" - yield mock_instance - - -def test_hevc_transcoding_scenario(mock_play_utils): - with patch("jellyfin_kodi.helper.playutils.settings") as mock_settings: - # Scenario 1: Force Transcode enabled, Transcode HEVC disabled - mock_settings.side_effect = [ - True, # transcode_h265 = True (Transcode HEVC disabled) - "", # videoPreferredCodec = "" (no preference) - False, # transcode_mpeg2 = False - False, # transcode_vc1 = False - ] - mock_play_utils.get_transcoding_video_codec.return_value = ( - "h264,mpeg4,mpeg2video,vc1" - ) - result_1 = mock_play_utils.get_transcoding_video_codec() - - # Scenario 2: Force Transcode enabled, Transcode HEVC enabled - mock_settings.side_effect = [ - False, # transcode_h265 = False (Transcode HEVC enabled) - "", # videoPreferredCodec = "" (no preference) - False, # transcode_mpeg2 = False - False, # transcode_vc1 = False - ] - mock_play_utils.get_transcoding_video_codec.return_value = ( - "h264,mpeg4,mpeg2video,vc1,hevc" - ) - result_2 = mock_play_utils.get_transcoding_video_codec() - - # Assertions - assert ( - "hevc" not in result_1 - ), "HEVC should not be in codec list when Transcode HEVC is disabled" - assert ( - "hevc" in result_2 - ), "HEVC should be in codec list when Transcode HEVC is enabled" - - # Ensure other codecs are present in both scenarios - for codec in ["h264", "mpeg4", "mpeg2video", "vc1"]: - assert ( - codec in result_1 - ), f"{codec} should be in codec list regardless of HEVC setting" - assert ( - codec in result_2 - ), f"{codec} should be in codec list regardless of HEVC setting" - - # Ensure the order is correct in both scenarios - assert ( - result_1 == "h264,mpeg4,mpeg2video,vc1" - ), "Codec order incorrect when HEVC is disabled" - assert ( - result_2 == "h264,mpeg4,mpeg2video,vc1,hevc" - ), "Codec order incorrect when HEVC is enabled" +def play_utils(): + class ApiClient: + class config: + data = {"auth.token": ""} + + yield PlayUtils({}, api_client=ApiClient) + + +class PatchedSettings: + # TODO: move settings helper to separate file + settings = {} + + def __init__(self): + self.clear() + + @classmethod + def __call__(cls, setting: str, value=None): + if value is None: + result = cls.settings[setting.replace(".bool", "")] + + if result and setting.endswith(".bool"): + result = result in ("true", "1", True) + + return result + + if setting.endswith(".bool"): + setting = setting.replace(".bool", "") + value = bool(value) + cls.settings[setting] = value + + @classmethod + def clear(cls): + cls.settings.clear() + # TODO: read defaults from settings.xml + cls.settings.setdefault("transcode_h265", False) + cls.settings.setdefault("videoPreferredCodec", "H264/AVC") + cls.settings.setdefault("transcode_mpeg2", False) + cls.settings.setdefault("transcode_vc1", False) + cls.settings.setdefault("audioPreferredCodec", "AAC") + cls.settings.setdefault("transcode_vp9", False) + cls.settings.setdefault("transcode_av1", False) + + +@pytest.fixture(autouse=True) +def mock_settings(monkeypatch): + patched = PatchedSettings() + monkeypatch.setattr(playutils, "settings", patched) @pytest.mark.parametrize( "transcode_h265, preferred_codec, expected_result", [ - (False, "", "h264,mpeg4,mpeg2video,vc1,hevc"), - (True, "", "h264,mpeg4,mpeg2video,vc1"), (False, "H265/HEVC", "hevc,h264,mpeg4,mpeg2video,vc1"), - (True, "H265/HEVC", "h264,mpeg4,mpeg2video,vc1"), - (False, "H264", "h264,mpeg4,mpeg2video,vc1,hevc"), - (True, "H264", "h264,mpeg4,mpeg2video,vc1"), - (False, "MPEG4", "mpeg4,h264,mpeg2video,vc1,hevc"), - (True, "MPEG4", "mpeg4,h264,mpeg2video,vc1"), + (True, "H265/HEVC", "hevc,h264,mpeg4,mpeg2video,vc1"), + (False, "H264/AVC", "h264,hevc,mpeg4,mpeg2video,vc1"), + (True, "H264/AVC", "h264,mpeg4,mpeg2video,vc1"), ], ) def test_get_transcoding_video_codec_settings( - mock_play_utils, transcode_h265, preferred_codec, expected_result + play_utils, transcode_h265, preferred_codec, expected_result ): - with patch("jellyfin_kodi.helper.playutils.settings") as mock_settings: - mock_settings.side_effect = [transcode_h265, preferred_codec] - mock_play_utils.get_transcoding_video_codec.return_value = expected_result - result = mock_play_utils.get_transcoding_video_codec() - assert result == expected_result + playutils.settings("transcode_h265", transcode_h265) + playutils.settings("videoPreferredCodec", preferred_codec) + + result = play_utils.get_transcoding_video_codec() + assert result == expected_result @pytest.mark.parametrize( "transcode_mpeg2, transcode_vc1, expected_result", [ - (False, False, "h264,mpeg4,mpeg2video,vc1,hevc"), - (True, False, "h264,mpeg4,vc1,hevc"), - (False, True, "h264,mpeg4,mpeg2video,hevc"), - (True, True, "h264,mpeg4,hevc"), + (False, False, "h264,hevc,mpeg4,mpeg2video,vc1"), + (True, False, "h264,hevc,mpeg4,vc1"), + (False, True, "h264,hevc,mpeg4,mpeg2video"), + (True, True, "h264,hevc,mpeg4"), ], ) def test_get_transcoding_video_codec_transcode_options( - mock_play_utils, transcode_mpeg2, transcode_vc1, expected_result + play_utils, transcode_mpeg2, transcode_vc1, expected_result ): - with patch("jellyfin_kodi.helper.playutils.settings") as mock_settings: - mock_settings.side_effect = [False, "", transcode_mpeg2, transcode_vc1] - mock_play_utils.get_transcoding_video_codec.return_value = expected_result - result = mock_play_utils.get_transcoding_video_codec() - assert result == expected_result + playutils.settings("transcode_mpeg2", transcode_mpeg2) + playutils.settings("transcode_vc1", transcode_vc1) + result = play_utils.get_transcoding_video_codec() + assert result == expected_result @pytest.mark.parametrize( "preferred_codec, expected_first, expected_second", [ ("H265/HEVC", "hevc", "h264"), - ("H264", "h264", "hevc"), - ("MPEG4", "mpeg4", "h264"), + ("H264/AVC", "h264", "hevc"), ], ) def test_get_transcoding_video_codec_order( - mock_play_utils, preferred_codec, expected_first, expected_second + play_utils, preferred_codec, expected_first, expected_second +): + playutils.settings("videoPreferredCodec", preferred_codec) + result = play_utils.get_transcoding_video_codec().split(",") + assert result[0] == expected_first, result + assert result[1] == expected_second, result + + +@pytest.mark.parametrize( + "preferred_codec, transcode_h265", + [ + ("H265/HEVC", True), + ("H265/HEVC", False), + ("H264/AVC", True), + ("H264/AVC", False), + ], +) +def test_get_transcoding_video_codec_no_duplicates( + play_utils, preferred_codec, transcode_h265 ): - with patch("jellyfin_kodi.helper.playutils.settings") as mock_settings: - mock_settings.side_effect = [False, preferred_codec] - mock_play_utils.get_transcoding_video_codec.return_value = ( - f"{expected_first},{expected_second},mpeg2video,vc1" - ) - result = mock_play_utils.get_transcoding_video_codec() - assert result.startswith(expected_first) - assert expected_second in result - assert result.index(expected_first) < result.index(expected_second) - - -def test_get_transcoding_video_codec_no_duplicates(mock_play_utils): - with patch("jellyfin_kodi.helper.playutils.settings") as mock_settings: - mock_settings.side_effect = [False, ""] - mock_play_utils.get_transcoding_video_codec.return_value = ( - "h264,mpeg4,mpeg2video,vc1,hevc" - ) - result = mock_play_utils.get_transcoding_video_codec() - assert result.count("hevc") == 1 - assert result.count("h264") == 1 - assert result.count("mpeg4") == 1 - assert result.count("mpeg2video") == 1 - assert result.count("vc1") == 1 - - -def test_get_transcoding_video_codec_empty_result(mock_play_utils): - with patch("jellyfin_kodi.helper.playutils.settings") as mock_settings: - mock_settings.side_effect = [True, ""] - mock_play_utils.get_transcoding_video_codec.return_value = "" - result = mock_play_utils.get_transcoding_video_codec() - assert result == "" - - -def test_get_transcoding_video_codec_single_codec(mock_play_utils): - with patch("jellyfin_kodi.helper.playutils.settings") as mock_settings: - mock_settings.side_effect = [True, "H264"] - mock_play_utils.get_transcoding_video_codec.return_value = "h264" - result = mock_play_utils.get_transcoding_video_codec() - assert result == "h264" - - -def test_get_transcoding_video_codec_unknown_preferred(mock_play_utils): - with patch("jellyfin_kodi.helper.playutils.settings") as mock_settings: - mock_settings.side_effect = [False, "UNKNOWN"] - mock_play_utils.get_transcoding_video_codec.return_value = ( - "h264,mpeg4,mpeg2video,vc1,hevc" - ) - result = mock_play_utils.get_transcoding_video_codec() - assert result == "h264,mpeg4,mpeg2video,vc1,hevc" + playutils.settings("videoPreferredCodec", preferred_codec) + playutils.settings("transcode_h265", transcode_h265) + result = play_utils.get_transcoding_video_codec().split(",") + assert len(result) == len(set(result)) @pytest.mark.parametrize( "transcode_h265, preferred_codec, transcode_mpeg2, transcode_vc1, expected_result", [ - (True, "H264", True, True, "h264,mpeg4"), + (True, "H264/AVC", True, True, "h264,mpeg4"), (False, "H265/HEVC", False, False, "hevc,h264,mpeg4,mpeg2video,vc1"), - (True, "MPEG4", True, False, "mpeg4,h264,vc1"), ], ) def test_get_transcoding_video_codec_combined_settings( - mock_play_utils, + play_utils, transcode_h265, preferred_codec, transcode_mpeg2, transcode_vc1, expected_result, ): - with patch("jellyfin_kodi.helper.playutils.settings") as mock_settings: - mock_settings.side_effect = [ - transcode_h265, - preferred_codec, - transcode_mpeg2, - transcode_vc1, - ] - mock_play_utils.get_transcoding_video_codec.return_value = expected_result - result = mock_play_utils.get_transcoding_video_codec() - assert result == expected_result + playutils.settings("transcode_h265", transcode_h265) + playutils.settings("videoPreferredCodec", preferred_codec) + playutils.settings("transcode_mpeg2", transcode_mpeg2) + playutils.settings("transcode_vc1", transcode_vc1) + + result = play_utils.get_transcoding_video_codec() + assert result == expected_result @pytest.mark.parametrize( - "transcode_h265, preferred_codec, expected_result", + "transcode_h265, expected_result", [ - (False, "", "h264,mpeg4,mpeg2video,vc1,hevc"), - (True, "", "h264,mpeg4,mpeg2video,vc1"), - (False, "H265/HEVC", "hevc,h264,mpeg4,mpeg2video,vc1"), - (True, "H265/HEVC", "h264,mpeg4,mpeg2video,vc1"), - (False, "H264", "h264,mpeg4,mpeg2video,vc1,hevc"), - (True, "H264", "h264,mpeg4,mpeg2video,vc1"), - (False, "MPEG4", "mpeg4,h264,mpeg2video,vc1,hevc"), - (True, "MPEG4", "mpeg4,h264,mpeg2video,vc1"), + (False, "h264,hevc,mpeg4,mpeg2video,vc1,vp9,av1"), + (True, "h264,mpeg4,mpeg2video,vc1,vp9,av1"), ], ) -def test_get_directplay_video_codec( - mock_play_utils, transcode_h265, preferred_codec, expected_result -): - with patch("jellyfin_kodi.helper.playutils.settings") as mock_settings: - mock_settings.side_effect = [transcode_h265, preferred_codec] - mock_play_utils.get_directplay_video_codec.return_value = expected_result - result = mock_play_utils.get_directplay_video_codec() - assert result == expected_result +def test_get_directplay_video_codec(play_utils, transcode_h265, expected_result): + playutils.settings("transcode_h265", transcode_h265) + result = play_utils.get_directplay_video_codec() + assert result == expected_result @pytest.mark.parametrize( "transcode_mpeg2, transcode_vc1, expected_result", [ - (False, False, "h264,mpeg4,mpeg2video,vc1,hevc"), - (True, False, "h264,mpeg4,vc1,hevc"), - (False, True, "h264,mpeg4,mpeg2video,hevc"), - (True, True, "h264,mpeg4,hevc"), + (False, False, "h264,hevc,mpeg4,mpeg2video,vc1,vp9,av1"), + (True, False, "h264,hevc,mpeg4,vc1,vp9,av1"), + (False, True, "h264,hevc,mpeg4,mpeg2video,vp9,av1"), + (True, True, "h264,hevc,mpeg4,vp9,av1"), ], ) def test_get_directplay_video_codec_transcode_options( - mock_play_utils, transcode_mpeg2, transcode_vc1, expected_result + play_utils, transcode_mpeg2, transcode_vc1, expected_result ): - with patch("jellyfin_kodi.helper.playutils.settings") as mock_settings: - mock_settings.side_effect = [False, "", transcode_mpeg2, transcode_vc1] - mock_play_utils.get_directplay_video_codec.return_value = expected_result - result = mock_play_utils.get_directplay_video_codec() - assert result == expected_result - - -def test_get_directplay_video_codec_no_duplicates(mock_play_utils): - with patch("jellyfin_kodi.helper.playutils.settings") as mock_settings: - mock_settings.side_effect = [False, ""] - mock_play_utils.get_directplay_video_codec.return_value = ( - "h264,mpeg4,mpeg2video,vc1,hevc" - ) - result = mock_play_utils.get_directplay_video_codec() - assert result.count("hevc") == 1 - assert result.count("h264") == 1 - assert result.count("mpeg4") == 1 - assert result.count("mpeg2video") == 1 - assert result.count("vc1") == 1 - - -def test_get_directplay_video_codec_empty_result(mock_play_utils): - with patch("jellyfin_kodi.helper.playutils.settings") as mock_settings: - mock_settings.side_effect = [True, ""] - mock_play_utils.get_directplay_video_codec.return_value = "" - result = mock_play_utils.get_directplay_video_codec() - assert result == "" - - -def test_get_directplay_video_codec_single_codec(mock_play_utils): - with patch("jellyfin_kodi.helper.playutils.settings") as mock_settings: - mock_settings.side_effect = [True, "H264"] - mock_play_utils.get_directplay_video_codec.return_value = "h264" - result = mock_play_utils.get_directplay_video_codec() - assert result == "h264" - - -def test_get_directplay_video_codec_unknown_preferred(mock_play_utils): - with patch("jellyfin_kodi.helper.playutils.settings") as mock_settings: - mock_settings.side_effect = [False, "UNKNOWN"] - mock_play_utils.get_directplay_video_codec.return_value = ( - "h264,mpeg4,mpeg2video,vc1,hevc" - ) - result = mock_play_utils.get_directplay_video_codec() - assert result == "h264,mpeg4,mpeg2video,vc1,hevc" + playutils.settings("transcode_mpeg2", transcode_mpeg2) + playutils.settings("transcode_vc1", transcode_vc1) + result = play_utils.get_directplay_video_codec() + assert result == expected_result + + +def test_get_directplay_video_codec_no_duplicates(play_utils): + result = play_utils.get_directplay_video_codec().split() + assert len(result) == len(set(result)) @pytest.mark.parametrize( - "transcode_h265, preferred_codec, transcode_mpeg2, transcode_vc1, expected_result", + "transcode_h265, transcode_mpeg2, transcode_vc1, transcode_vp9, transcode_av1, expected_result", [ - (True, "H264", True, True, "h264,mpeg4"), - (False, "H265/HEVC", False, False, "hevc,h264,mpeg4,mpeg2video,vc1"), - (True, "MPEG4", True, False, "mpeg4,h264,vc1"), + (True, True, True, True, True, "h264,mpeg4"), + (False, False, False, False, False, "h264,hevc,mpeg4,mpeg2video,vc1,vp9,av1"), ], ) def test_get_directplay_video_codec_combined_settings( - mock_play_utils, + play_utils, transcode_h265, - preferred_codec, transcode_mpeg2, transcode_vc1, + transcode_vp9, + transcode_av1, expected_result, ): - with patch("jellyfin_kodi.helper.playutils.settings") as mock_settings: - mock_settings.side_effect = [ - transcode_h265, - preferred_codec, - transcode_mpeg2, - transcode_vc1, - ] - mock_play_utils.get_directplay_video_codec.return_value = expected_result - result = mock_play_utils.get_directplay_video_codec() - assert result == expected_result + playutils.settings("transcode_h265", transcode_h265) + playutils.settings("transcode_mpeg2", transcode_mpeg2) + playutils.settings("transcode_vc1", transcode_vc1) + playutils.settings("transcode_vp9", transcode_vp9) + playutils.settings("transcode_av1", transcode_av1) + result = play_utils.get_directplay_video_codec() + assert result == expected_result @pytest.mark.parametrize( @@ -318,76 +223,24 @@ def test_get_directplay_video_codec_combined_settings( ("UNKNOWN", "aac,mp3,ac3,opus,flac,vorbis"), ], ) -def test_get_transcoding_audio_codec(mock_play_utils, preferred_codec, expected_result): - with patch("jellyfin_kodi.helper.playutils.settings") as mock_settings: - mock_settings.return_value = preferred_codec - mock_play_utils.get_transcoding_audio_codec.return_value = expected_result - result = mock_play_utils.get_transcoding_audio_codec() - assert result == expected_result - - -def test_get_transcoding_audio_codec_case_insensitive(mock_play_utils): - with patch("jellyfin_kodi.helper.playutils.settings") as mock_settings: - mock_settings.return_value = "aAc" - mock_play_utils.get_transcoding_audio_codec.return_value = ( - "aac,mp3,ac3,opus,flac,vorbis" - ) - result = mock_play_utils.get_transcoding_audio_codec() - assert result == "aac,mp3,ac3,opus,flac,vorbis" - - -def test_get_transcoding_audio_codec_no_duplicates(mock_play_utils): - with patch("jellyfin_kodi.helper.playutils.settings") as mock_settings: - mock_settings.return_value = "" - mock_play_utils.get_transcoding_audio_codec.return_value = ( - "aac,mp3,ac3,opus,flac,vorbis" - ) - result = mock_play_utils.get_transcoding_audio_codec() - assert result.count("aac") == 1 - assert result.count("mp3") == 1 - assert result.count("ac3") == 1 - assert result.count("opus") == 1 - assert result.count("flac") == 1 - assert result.count("vorbis") == 1 - - -def test_get_transcoding_audio_codec_empty_result(mock_play_utils): - with patch("jellyfin_kodi.helper.playutils.settings") as mock_settings: - mock_settings.return_value = "" - mock_play_utils.get_transcoding_audio_codec.return_value = "" - result = mock_play_utils.get_transcoding_audio_codec() - assert result == "" - - -def test_get_transcoding_audio_codec_single_codec(mock_play_utils): - with patch("jellyfin_kodi.helper.playutils.settings") as mock_settings: - mock_settings.return_value = "AAC" - mock_play_utils.get_transcoding_audio_codec.return_value = "aac" - result = mock_play_utils.get_transcoding_audio_codec() - assert result == "aac" - - -def test_get_transcoding_audio_codec_preserve_order(mock_play_utils): - with patch("jellyfin_kodi.helper.playutils.settings") as mock_settings: - mock_settings.return_value = "" - mock_play_utils.get_transcoding_audio_codec.return_value = ( - "aac,mp3,ac3,opus,flac,vorbis" - ) - result = mock_play_utils.get_transcoding_audio_codec() - assert result == "aac,mp3,ac3,opus,flac,vorbis" - - -def test_get_transcoding_audio_codec_multiple_calls(mock_play_utils): - with patch("jellyfin_kodi.helper.playutils.settings") as mock_settings: - mock_settings.side_effect = ["AAC", "MP3", "FLAC"] - mock_play_utils.get_transcoding_audio_codec.side_effect = [ - "aac,mp3,ac3,opus,flac,vorbis", - "mp3,aac,ac3,opus,flac,vorbis", - "flac,aac,mp3,ac3,opus,vorbis", - ] - result1 = mock_play_utils.get_transcoding_audio_codec() - result2 = mock_play_utils.get_transcoding_audio_codec() - result3 = mock_play_utils.get_transcoding_audio_codec() - assert result1 == "aac,mp3,ac3,opus,flac,vorbis" - assert result2 == "mp3,aac,ac3,opus,flac,vorbis" - assert result3 == "flac,aac,mp3,ac3,opus,vorbis" +def test_get_transcoding_audio_codec(play_utils, preferred_codec, expected_result): + playutils.settings("audioPreferredCodec", preferred_codec) + result = play_utils.get_transcoding_audio_codec() + assert result == expected_result + + +def test_get_transcoding_audio_codec_case_insensitive(play_utils): + playutils.settings("audioPreferredCodec", "aAc") + result = play_utils.get_transcoding_audio_codec() + assert result == "aac,mp3,ac3,opus,flac,vorbis" + + +def test_get_transcoding_audio_codec_no_duplicates(play_utils): + result = play_utils.get_transcoding_audio_codec().split(",") + assert len(result) == len(set(result)) + + +def test_get_transcoding_audio_codec_preserve_order(play_utils): + playutils.settings("audioPreferredCodec", "") + result = play_utils.get_transcoding_audio_codec() + assert result == "aac,mp3,ac3,opus,flac,vorbis" From 9eb9cd1e6188a4bf68cdf982f6696ca5ff319e79 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Odd=20Str=C3=A5b=C3=B8?= Date: Sat, 10 Aug 2024 10:24:10 +0000 Subject: [PATCH 4/4] Simplify logic --- jellyfin_kodi/helper/playutils.py | 9 +++------ tests/test_playutils_settings.py | 1 + 2 files changed, 4 insertions(+), 6 deletions(-) diff --git a/jellyfin_kodi/helper/playutils.py b/jellyfin_kodi/helper/playutils.py index b17acb268..1c8a3c2dd 100644 --- a/jellyfin_kodi/helper/playutils.py +++ b/jellyfin_kodi/helper/playutils.py @@ -385,13 +385,10 @@ def get_directplay_video_codec(self): def get_transcoding_video_codec(self): codecs = ["h264", "mpeg4", "mpeg2video", "vc1"] - if not settings("transcode_h265.bool"): - codecs.insert(1, "hevc") # Add HEVC if transcoding is not forced - if settings("videoPreferredCodec") == "H265/HEVC": - if "hevc" in codecs: - codecs.remove("hevc") - codecs.insert(0, "hevc") # Add HEVC at the beginning if preferred + codecs.insert(0, "hevc") + elif not settings("transcode_h265.bool"): + codecs.insert(1, "hevc") if settings("transcode_mpeg2.bool"): codecs.remove("mpeg2video") diff --git a/tests/test_playutils_settings.py b/tests/test_playutils_settings.py index 9cdcfa5d7..22ab678ef 100644 --- a/tests/test_playutils_settings.py +++ b/tests/test_playutils_settings.py @@ -34,6 +34,7 @@ def __call__(cls, setting: str, value=None): setting = setting.replace(".bool", "") value = bool(value) cls.settings[setting] = value + return None @classmethod def clear(cls):