forked from kenzuya/unshackle
feat(movie): improve non-scene filename sanitization
Add dedicated non-scene filename sanitization for movies to produce cleaner, filesystem-safe names when `scene_naming` is disabled. The new logic: - optionally transliterates unicode based on `unicode_filenames` - removes combining marks/diacritics and disallowed punctuation - normalizes separators and extra whitespace Also update movie name construction to explicitly format `Name (Year)` and append a trailing ` -` for non-scene naming before metadata tokens, improving readability and consistency. Update default config values in `unshackle.yaml` to match non-scene/local usage: - disable `scene_naming` by default - comment out default `tag` - change downloads directory to `Downloads`feat(movie): improve non-scene filename sanitization Add dedicated non-scene filename sanitization for movies to produce cleaner, filesystem-safe names when `scene_naming` is disabled. The new logic: - optionally transliterates unicode based on `unicode_filenames` - removes combining marks/diacritics and disallowed punctuation - normalizes separators and extra whitespace Also update movie name construction to explicitly format `Name (Year)` and append a trailing ` -` for non-scene naming before metadata tokens, improving readability and consistency. Update default config values in `unshackle.yaml` to match non-scene/local usage: - disable `scene_naming` by default - comment out default `tag` - change downloads directory to `Downloads`
This commit is contained in:
@@ -1,3 +1,5 @@
|
|||||||
|
import re
|
||||||
|
import unicodedata
|
||||||
from abc import ABC
|
from abc import ABC
|
||||||
from typing import Any, Iterable, Optional, Union
|
from typing import Any, Iterable, Optional, Union
|
||||||
|
|
||||||
@@ -5,6 +7,7 @@ from langcodes import Language
|
|||||||
from pymediainfo import MediaInfo
|
from pymediainfo import MediaInfo
|
||||||
from rich.tree import Tree
|
from rich.tree import Tree
|
||||||
from sortedcontainers import SortedKeyList
|
from sortedcontainers import SortedKeyList
|
||||||
|
from unidecode import unidecode
|
||||||
|
|
||||||
from unshackle.core.config import config
|
from unshackle.core.config import config
|
||||||
from unshackle.core.constants import AUDIO_CODEC_MAP, DYNAMIC_RANGE_MAP, VIDEO_CODEC_MAP
|
from unshackle.core.constants import AUDIO_CODEC_MAP, DYNAMIC_RANGE_MAP, VIDEO_CODEC_MAP
|
||||||
@@ -52,6 +55,18 @@ class Movie(Title):
|
|||||||
return f"{self.name} ({self.year})"
|
return f"{self.name} ({self.year})"
|
||||||
return self.name
|
return self.name
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def _sanitize_non_scene_filename(filename: str) -> str:
|
||||||
|
if not config.unicode_filenames:
|
||||||
|
filename = unidecode(filename)
|
||||||
|
|
||||||
|
filename = "".join(c for c in filename if unicodedata.category(c) != "Mn")
|
||||||
|
filename = filename.replace("/", " & ").replace(";", " & ")
|
||||||
|
filename = re.sub(r"[\\:*!?¿,'\"<>|$#~]", "", filename)
|
||||||
|
filename = re.sub(r"\s{2,}", " ", filename)
|
||||||
|
|
||||||
|
return filename.strip()
|
||||||
|
|
||||||
def get_filename(self, media_info: MediaInfo, folder: bool = False, show_service: bool = True) -> str:
|
def get_filename(self, media_info: MediaInfo, folder: bool = False, show_service: bool = True) -> str:
|
||||||
primary_video_track = next(iter(media_info.video_tracks), None)
|
primary_video_track = next(iter(media_info.video_tracks), None)
|
||||||
primary_audio_track = None
|
primary_audio_track = None
|
||||||
@@ -89,7 +104,11 @@ class Movie(Title):
|
|||||||
return f"{resolution}{scan_suffix}"
|
return f"{resolution}{scan_suffix}"
|
||||||
|
|
||||||
# Name (Year)
|
# Name (Year)
|
||||||
name = str(self).replace("$", "S") # e.g., Arli$$
|
name = self.name.replace("$", "S") # e.g., Arli$$
|
||||||
|
if self.year:
|
||||||
|
name = f"{name} ({self.year})"
|
||||||
|
if not config.scene_naming:
|
||||||
|
name += " -"
|
||||||
|
|
||||||
if primary_video_track:
|
if primary_video_track:
|
||||||
resolution_token = _get_resolution_token(primary_video_track)
|
resolution_token = _get_resolution_token(primary_video_track)
|
||||||
@@ -179,7 +198,9 @@ class Movie(Title):
|
|||||||
if config.tag:
|
if config.tag:
|
||||||
name += f"-{config.tag}"
|
name += f"-{config.tag}"
|
||||||
|
|
||||||
return sanitize_filename(name, "." if config.scene_naming else " ")
|
if config.scene_naming:
|
||||||
|
return sanitize_filename(name, ".")
|
||||||
|
return self._sanitize_non_scene_filename(name)
|
||||||
|
|
||||||
|
|
||||||
class Movies(SortedKeyList, ABC):
|
class Movies(SortedKeyList, ABC):
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
# Group or Username to postfix to the end of all download filenames following a dash
|
# Group or Username to postfix to the end of all download filenames following a dash
|
||||||
tag: Kenzuya
|
# tag: Kenzuya
|
||||||
|
|
||||||
# Enable/disable tagging with group name (default: true)
|
# Enable/disable tagging with group name (default: true)
|
||||||
tag_group_name: true
|
tag_group_name: true
|
||||||
@@ -13,7 +13,7 @@ set_terminal_bg: false
|
|||||||
# Set file naming convention
|
# Set file naming convention
|
||||||
# true for style - Prime.Suspect.S07E01.The.Final.Act.Part.One.1080p.ITV.WEB-DL.AAC2.0.H.264
|
# true for style - Prime.Suspect.S07E01.The.Final.Act.Part.One.1080p.ITV.WEB-DL.AAC2.0.H.264
|
||||||
# false for style - Prime Suspect S07E01 The Final Act - Part One
|
# false for style - Prime Suspect S07E01 The Final Act - Part One
|
||||||
scene_naming: true
|
scene_naming: false
|
||||||
|
|
||||||
# Whether to include the year in series names for episodes and folders (default: true)
|
# Whether to include the year in series names for episodes and folders (default: true)
|
||||||
# true for style - Show Name (2023) S01E01 Episode Name
|
# true for style - Show Name (2023) S01E01 Episode Name
|
||||||
@@ -64,7 +64,7 @@ directories:
|
|||||||
cache: Cache
|
cache: Cache
|
||||||
# cookies: Cookies
|
# cookies: Cookies
|
||||||
dcsl: DCSL # Device Certificate Status List
|
dcsl: DCSL # Device Certificate Status List
|
||||||
downloads: /home/kenzuya/Mounts/ketuakenzuya/Downloads
|
downloads: Downloads
|
||||||
logs: Logs
|
logs: Logs
|
||||||
temp: Temp
|
temp: Temp
|
||||||
# wvds: WVDs
|
# wvds: WVDs
|
||||||
|
|||||||
Reference in New Issue
Block a user