30
30
from collections import Counter
31
31
from contextlib import suppress
32
32
from enum import Enum
33
+ from functools import cache
33
34
from importlib import import_module
34
35
from multiprocessing .pool import ThreadPool
35
36
from pathlib import Path
47
48
48
49
from unidecode import unidecode
49
50
51
+ import beets
50
52
from beets .util import hidden
51
53
52
54
if TYPE_CHECKING :
@@ -694,25 +696,26 @@ def sanitize_path(path: str, replacements: Replacements | None = None) -> str:
694
696
return os .path .join (* comps )
695
697
696
698
697
- def truncate_path (path : AnyStr , length : int = MAX_FILENAME_LENGTH ) -> AnyStr :
699
+ def truncate_path (path : AnyStr ) -> AnyStr :
698
700
"""Given a bytestring path or a Unicode path fragment, truncate the
699
701
components to a legal length. In the last component, the extension
700
702
is preserved.
701
703
"""
704
+ max_length = get_max_filename_length ()
702
705
comps = components (path )
703
706
704
707
out = [c [:length ] for c in comps ]
705
708
base , ext = os .path .splitext (comps [- 1 ])
706
709
if ext :
707
710
# Last component has an extension.
708
- base = base [: length - len (ext )]
711
+ base = base [: max_length - len (ext )]
709
712
out [- 1 ] = base + ext
710
713
711
714
return os .path .join (* out )
712
715
713
716
714
717
def _legalize_stage (
715
- path : str , replacements : Replacements | None , length : int , extension : str
718
+ path : str , replacements : Replacements | None , extension : str
716
719
) -> tuple [str , bool ]:
717
720
"""Perform a single round of path legalization steps
718
721
1. sanitation/replacement
@@ -729,13 +732,13 @@ def _legalize_stage(
729
732
730
733
# Truncate too-long components.
731
734
pre_truncate_path = path
732
- path = truncate_path (path , length )
735
+ path = truncate_path (path )
733
736
734
737
return path , path != pre_truncate_path
735
738
736
739
737
740
def legalize_path (
738
- path : str , replacements : Replacements | None , length : int , extension : str
741
+ path : str , replacements : Replacements | None , extension : str
739
742
) -> tuple [str , bool ]:
740
743
"""Given a path-like Unicode string, produce a legal path. Return the path
741
744
and a flag indicating whether some replacements had to be ignored (see
@@ -755,21 +758,21 @@ def legalize_path(
755
758
after it was truncated); the application should probably log some sort of
756
759
warning.
757
760
"""
758
- args = length , as_string (extension )
761
+ suffix = as_string (extension )
759
762
760
763
first_stage , _ = os .path .splitext (
761
- _legalize_stage (path , replacements , * args )[0 ]
764
+ _legalize_stage (path , replacements , suffix )[0 ]
762
765
)
763
766
764
767
# Re-sanitize following truncation (including user replacements).
765
- second_stage , truncated = _legalize_stage (first_stage , replacements , * args )
768
+ second_stage , truncated = _legalize_stage (first_stage , replacements , suffix )
766
769
767
770
if not truncated :
768
771
return second_stage , False
769
772
770
773
# If the path was truncated, discard user replacements
771
774
# and run through one last legalization stage.
772
- return _legalize_stage (first_stage , None , * args )[0 ], True
775
+ return _legalize_stage (first_stage , None , suffix )[0 ], True
773
776
774
777
775
778
def str2bool (value : str ) -> bool :
@@ -848,16 +851,21 @@ def command_output(cmd: list[BytesOrStr], shell: bool = False) -> CommandOutput:
848
851
return CommandOutput (stdout , stderr )
849
852
850
853
851
- def max_filename_length (path : BytesOrStr , limit = MAX_FILENAME_LENGTH ) -> int :
854
+ @cache
855
+ def get_max_filename_length () -> int :
852
856
"""Attempt to determine the maximum filename length for the
853
857
filesystem containing `path`. If the value is greater than `limit`,
854
858
then `limit` is used instead (to prevent errors when a filesystem
855
859
misreports its capacity). If it cannot be determined (e.g., on
856
860
Windows), return `limit`.
857
861
"""
862
+ if length := beets .config ["max_filename_length" ].get (int ):
863
+ return length
864
+
865
+ limit = MAX_FILENAME_LENGTH
858
866
if hasattr (os , "statvfs" ):
859
867
try :
860
- res = os .statvfs (path )
868
+ res = os .statvfs (beets . config [ "directory" ]. as_str () )
861
869
except OSError :
862
870
return limit
863
871
return min (res [9 ], limit )
0 commit comments