Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
35 changes: 31 additions & 4 deletions whipper/common/common.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
# along with whipper. If not, see <http://www.gnu.org/licenses/>.


from pathlib import Path
import os
import os.path
import math
Expand Down Expand Up @@ -151,12 +152,38 @@ class MissingFrames(Exception):
pass


def truncate_filename(path):
"""Truncate filename to the max. len. allowed by the path's filesystem."""
def truncate_filename(path, has_file_ext=True):
"""
Truncate filename to the maximum length allowed by the path's filesystem.

:param path: path to truncate
:param has_file_ext: if True, will keep the file extension intact;
set to False for:
- directories (which may contain dots but do not have an
extension),
- filenames without a file extension (dots will be
considered like normal characters)
:type path: str
:type has_file_ext: bool
"""
p, f = os.path.split(os.path.normpath(path))
f, e = os.path.splitext(f)
if has_file_ext:
f, e = os.path.splitext(f)
else:
f, e = (f, '')
# Get the filename length limit in bytes
fn_lim = os.pathconf(p.encode('utf-8'), 'PC_NAME_MAX')
def get_existing_parent(path):
for p in [Path(path)] + list(Path(path).parents):
if p.exists():
return str(p)
try:
fn_lim = os.pathconf(get_existing_parent(p).encode('utf-8'), 'PC_NAME_MAX')
except OSError as e:
import errno
if e.errno == errno.EINVAL:
fn_lim = 255
else:
raise
f_max = fn_lim - len(e.encode('utf-8'))
f = unicodedata.normalize('NFC', f)
f_trunc = f.encode()[:f_max].decode('utf-8', errors='ignore')
Expand Down
9 changes: 6 additions & 3 deletions whipper/common/program.py
Original file line number Diff line number Diff line change
Expand Up @@ -241,9 +241,12 @@ def getPath(self, outdir, template, mbdiscid, metadata, track_number=None):
# Avoid filtering non str type values, replace None with empty string
v_fltr = {k: self._filter.filter(v2) if isinstance(v2, str) else ''
if v2 is None else v2 for k, v2 in v.items()}
if outdir == os.curdir:
return template % v_fltr # Avoid useless './' in file paths
return os.path.join(outdir, template % v_fltr)
parts = (template % v_fltr).split('/')
truncated_path = os.path.join(*
[common.truncate_filename(p, has_file_ext=False) for p in parts])
if outdir != os.curdir: # Avoid useless './' in file paths
truncated_path = os.path.join(outdir, truncated_path)
return truncated_path

@staticmethod
def getCDDB(cddbdiscid):
Expand Down