[BUGFIX] File name too long with -thumb.jpg, upgrade docker alpine image (#560)

This commit is contained in:
Jesse Bannon
2023-03-24 11:15:54 -07:00
committed by GitHub
parent 70d81bf20f
commit 84cd611f89
5 changed files with 55 additions and 17 deletions

View File

@@ -1,4 +1,4 @@
FROM ghcr.io/linuxserver/baseimage-alpine:3.17 FROM ghcr.io/linuxserver/baseimage-alpine:edge
############################################################################### ###############################################################################
# YTDL-SUB INSTALL # YTDL-SUB INSTALL
@@ -12,7 +12,7 @@ RUN mkdir -p /config && \
g++ \ g++ \
nano \ nano \
make \ make \
python3=~3.10 \ "python3>=3.10" \
py3-pip \ py3-pip \
fontconfig \ fontconfig \
py3-setuptools && \ py3-setuptools && \
@@ -30,13 +30,14 @@ RUN mkdir -p /config && \
cd -; \ cd -; \
fi && \ fi && \
# Install ytdl-sub, ensure it is installed properly # Install ytdl-sub, ensure it is installed properly
pip install --no-cache-dir ytdl_sub-*.whl && \ python3 -m pip install --no-cache-dir ytdl_sub-*.whl && \
ytdl-sub -h && \ ytdl-sub -h && \
# Delete unneeded packages after install # Delete unneeded packages after install
rm ytdl_sub-*.whl && \ rm ytdl_sub-*.whl && \
apk del \ apk del \
g++ \ g++ \
make \ make \
py3-pip \
py3-setuptools py3-setuptools
############################################################################### ###############################################################################

View File

@@ -15,6 +15,7 @@ classifiers =
License :: Public Domain License :: Public Domain
Environment :: Console Environment :: Console
Programming Language :: Python :: 3.10 Programming Language :: Python :: 3.10
Programming Language :: Python :: 3.11
[options.entry_points] [options.entry_points]
console_scripts = console_scripts =

View File

@@ -1,2 +1,2 @@
__pypi_version__ = "2023.03.15" __pypi_version__ = "2023.03.24.post7"
__local_version__ = "2023.03.15+e69933d" __local_version__ = "2023.03.24+14e4a4b"

View File

@@ -16,6 +16,9 @@ if IS_WINDOWS:
else: else:
_MAX_FILE_NAME_BYTES = os.pathconf("/", "PC_NAME_MAX") _MAX_FILE_NAME_BYTES = os.pathconf("/", "PC_NAME_MAX")
# Save file-name bytes for the -thumb.jpg portion
_MAX_BASE_FILE_NAME_BYTES = _MAX_FILE_NAME_BYTES - len("-thumb.jpg".encode("utf-8")) - 8
class FFmpegFileValidator(StringValidator): class FFmpegFileValidator(StringValidator):
_expected_value_type_name = "ffmpeg dependency" _expected_value_type_name = "ffmpeg dependency"
@@ -90,17 +93,24 @@ class StringFormatterFileNameValidator(StringFormatterValidator, FilePathValidat
@classmethod @classmethod
def _get_extension_split(cls, file_name: str) -> Tuple[str, str]: def _get_extension_split(cls, file_name: str) -> Tuple[str, str]:
"""
Returns
-------
file_name, ext (including .)
"""
if file_name.endswith(".info.json"): if file_name.endswith(".info.json"):
ext = "info.json" ext = ".info.json"
elif file_name.endswith("-thumb.jpg"):
ext = "-thumb.jpg"
elif any(file_name.endswith(f".{subtitle_ext}") for subtitle_ext in SUBTITLE_EXTENSIONS): elif any(file_name.endswith(f".{subtitle_ext}") for subtitle_ext in SUBTITLE_EXTENSIONS):
file_name_split = file_name.split(".") file_name_split = file_name.split(".")
ext = file_name_split[-1] ext = file_name_split[-1]
# Try to capture .lang.ext # Try to capture .lang.ext
if len(file_name_split) > 2 and len(file_name_split[-2]) < 6: if len(file_name_split) > 2 and len(file_name_split[-2]) < 6:
ext = f"{file_name_split[-2]}.{file_name_split[-1]}" ext = f".{file_name_split[-2]}.{file_name_split[-1]}"
else: else:
ext = file_name.rsplit(".", maxsplit=1)[-1] ext = f".{file_name.rsplit('.', maxsplit=1)[-1]}"
return file_name[: -len(ext)], ext return file_name[: -len(ext)], ext
@@ -108,11 +118,10 @@ class StringFormatterFileNameValidator(StringFormatterValidator, FilePathValidat
def _truncate_file_name(cls, file_name: str) -> str: def _truncate_file_name(cls, file_name: str) -> str:
file_sub_name, file_ext = cls._get_extension_split(file_name) file_sub_name, file_ext = cls._get_extension_split(file_name)
desired_size = _MAX_FILE_NAME_BYTES - len(file_ext.encode("utf-8")) - 1 while len(file_sub_name.encode("utf-8")) > _MAX_BASE_FILE_NAME_BYTES:
while len(file_sub_name.encode("utf-8")) > desired_size:
file_sub_name = file_sub_name[:-1] file_sub_name = file_sub_name[:-1]
return f"{file_sub_name}.{file_ext}" return f"{file_sub_name}{file_ext}"
def apply_formatter(self, variable_dict: Dict[str, str]) -> str: def apply_formatter(self, variable_dict: Dict[str, str]) -> str:
"""Turn into a Path, then a string, to get correct directory separators""" """Turn into a Path, then a string, to get correct directory separators"""

View File

@@ -10,18 +10,16 @@ from ytdl_sub.validators.file_path_validators import StringFormatterFileNameVali
class TestStringFormatterFilePathValidator: class TestStringFormatterFilePathValidator:
@pytest.mark.parametrize( @pytest.mark.parametrize(
"ext", "ext",
[ ["mp4", "info.json", "-thumb.jpg"] + [f"en-US.{ext}" for ext in SUBTITLE_EXTENSIONS],
"mp4",
"info.json",
]
+ [f"en-US.{ext}" for ext in SUBTITLE_EXTENSIONS],
) )
@pytest.mark.parametrize("file_name_char", ["a", "𒃀"]) @pytest.mark.parametrize("file_name_char", ["a", "𒃀"])
@pytest.mark.parametrize("file_name_len", [10, 10000]) @pytest.mark.parametrize("file_name_len", [10, 10000])
def test_truncates_file_name_successfully( def test_truncates_file_name_successfully(
self, ext: str, file_name_char: str, file_name_len: int self, ext: str, file_name_char: str, file_name_len: int
): ):
ext = f".{ext}" # pytest args with . in the beginning act weird if "thumb" not in ext: # do not put . in front of -thumb
ext = f".{ext}" # pytest args with . in the beginning act weird
with tempfile.TemporaryDirectory() as temp_dir: with tempfile.TemporaryDirectory() as temp_dir:
file_name = (file_name_char * file_name_len) + ext file_name = (file_name_char * file_name_len) + ext
file_path = str(Path(temp_dir) / file_name) file_path = str(Path(temp_dir) / file_name)
@@ -40,3 +38,32 @@ class TestStringFormatterFilePathValidator:
assert len(dir_paths) == 1 assert len(dir_paths) == 1
assert Path(truncated_file_path) == dir_paths[0] assert Path(truncated_file_path) == dir_paths[0]
@pytest.mark.parametrize(
"ext",
["mp4", "info.json", "-thumb.jpg"] + [f"en-US.{ext}" for ext in SUBTITLE_EXTENSIONS],
)
def test_truncates_file_names_successfully(self, ext: str):
if "thumb" not in ext: # do not put . in front of -thumb
ext = f".{ext}" # pytest args with . in the beginning act weird
base_file_name = "s2023.e031701 - 𝗪𝗔𝗥𝗡𝗜𝗡𝗚 LG Secretly Overhaul This OLED Feature on C & G… Should You Buy C Instead"
with tempfile.TemporaryDirectory() as temp_dir:
file_path = str(Path(temp_dir) / f"{base_file_name}{ext}")
formatter = StringFormatterFileNameValidator(name="test", value=str(file_path))
truncated_file_path = formatter.apply_formatter({})
assert truncated_file_path == str(
Path(temp_dir)
/ f"s2023.e031701 - 𝗪𝗔𝗥𝗡𝗜𝗡𝗚 LG Secretly Overhaul This OLED Feature on C & G… Should You Buy C Instead{ext}"
)
# Ensure it can actually open the file
with open(truncated_file_path, "w", encoding="utf-8"):
# Make sure the file is actually in the directory
dir_paths = list(Path(temp_dir).rglob("*"))
assert len(dir_paths) == 1
assert Path(truncated_file_path) == dir_paths[0]