Merge pull request #431 from Mbucari/master
Fix file naming template on unix systems (#430)
This commit is contained in:
commit
a0158db37e
@ -44,12 +44,20 @@ namespace FileManager
|
||||
var fileNamePart = pathParts[^1];
|
||||
pathParts.Remove(fileNamePart);
|
||||
|
||||
var fileExtension = Path.GetExtension(fileNamePart);
|
||||
fileNamePart = fileNamePart[..^fileExtension.Length];
|
||||
|
||||
LongPath directory = Path.Join(pathParts.Select(p => replaceFileName(p, paramReplacements, LongPath.MaxFilenameLength)).ToArray());
|
||||
|
||||
//If file already exists, GetValidFilename will append " (n)" to the filename.
|
||||
//This could cause the filename length to exceed MaxFilenameLength, so reduce
|
||||
//allowable filename length by 5 chars, allowing for up to 99 duplicates.
|
||||
return FileUtility.GetValidFilename(Path.Join(directory, replaceFileName(fileNamePart, paramReplacements, LongPath.MaxFilenameLength - 5)), replacements, returnFirstExisting);
|
||||
return FileUtility
|
||||
.GetValidFilename(
|
||||
Path.Join(directory, replaceFileName(fileNamePart, paramReplacements, LongPath.MaxFilenameLength - fileExtension.Length - 5)) + fileExtension,
|
||||
replacements,
|
||||
returnFirstExisting
|
||||
);
|
||||
}
|
||||
|
||||
private static string replaceFileName(string filename, Dictionary<string,string> paramReplacements, int maxFilenameLength)
|
||||
@ -88,7 +96,7 @@ namespace FileManager
|
||||
|
||||
//Remove 1 character from the end of the longest filename part until
|
||||
//the total filename is less than max filename length
|
||||
while (filenameParts.Sum(p => p.Length) > maxFilenameLength)
|
||||
while (filenameParts.Sum(p => LongPath.GetFilesystemStringLength(p)) > maxFilenameLength)
|
||||
{
|
||||
int maxLength = filenameParts.Max(p => p.Length);
|
||||
var maxEntry = filenameParts.First(p => p.Length == maxLength);
|
||||
|
||||
@ -6,11 +6,14 @@ using System.Text.RegularExpressions;
|
||||
using Dinah.Core;
|
||||
using Polly;
|
||||
using Polly.Retry;
|
||||
using Dinah.Core.Collections.Generic;
|
||||
|
||||
namespace FileManager
|
||||
{
|
||||
public static class FileUtility
|
||||
{
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// "txt" => ".txt"
|
||||
/// <br />".txt" => ".txt"
|
||||
@ -55,15 +58,15 @@ namespace FileManager
|
||||
|
||||
// ensure uniqueness and check lengths
|
||||
var dir = Path.GetDirectoryName(path);
|
||||
dir = dir?.Truncate(LongPath.MaxDirectoryLength) ?? string.Empty;
|
||||
dir = dir?.TruncateFilename(LongPath.MaxDirectoryLength) ?? string.Empty;
|
||||
|
||||
var extension = Path.GetExtension(path);
|
||||
|
||||
var filename = Path.GetFileNameWithoutExtension(path).Truncate(LongPath.MaxFilenameLength - extension.Length);
|
||||
var filename = Path.GetFileNameWithoutExtension(path).TruncateFilename(LongPath.MaxFilenameLength - extension.Length);
|
||||
var fileStem = Path.Combine(dir, filename);
|
||||
|
||||
|
||||
var fullfilename = fileStem.Truncate(LongPath.MaxPathLength - extension.Length) + extension;
|
||||
var fullfilename = fileStem.TruncateFilename(LongPath.MaxPathLength - extension.Length) + extension;
|
||||
|
||||
fullfilename = removeInvalidWhitespace(fullfilename);
|
||||
|
||||
@ -71,7 +74,7 @@ namespace FileManager
|
||||
while (File.Exists(fullfilename) && !returnFirstExisting)
|
||||
{
|
||||
var increm = $" ({++i})";
|
||||
fullfilename = fileStem.Truncate(LongPath.MaxPathLength - increm.Length - extension.Length) + increm + extension;
|
||||
fullfilename = fileStem.TruncateFilename(LongPath.MaxPathLength - increm.Length - extension.Length) + increm + extension;
|
||||
}
|
||||
|
||||
return fullfilename;
|
||||
@ -129,6 +132,18 @@ namespace FileManager
|
||||
|
||||
public static string RemoveLastCharacter(this string str) => string.IsNullOrEmpty(str) ? str : str[..^1];
|
||||
|
||||
public static string TruncateFilename(this string filenameStr, int limit)
|
||||
{
|
||||
if (LongPath.IsWindows) return filenameStr.Truncate(limit);
|
||||
|
||||
int index = filenameStr.Length;
|
||||
|
||||
while (index > 0 && System.Text.Encoding.UTF8.GetByteCount(filenameStr, 0, index) > limit)
|
||||
index--;
|
||||
|
||||
return filenameStr[..index];
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Move file.
|
||||
/// <br/>- Ensure valid file name path: remove invalid chars, ensure uniqueness, enforce max file length
|
||||
|
||||
@ -10,22 +10,59 @@ namespace FileManager
|
||||
{
|
||||
//https://docs.microsoft.com/en-us/windows/win32/fileio/maximum-file-path-limitation?tabs=cmd
|
||||
|
||||
public const int MaxDirectoryLength = MaxPathLength - 13;
|
||||
public const int MaxPathLength = short.MaxValue;
|
||||
public const int MaxFilenameLength = 255;
|
||||
public static readonly int MaxDirectoryLength;
|
||||
public static readonly int MaxPathLength;
|
||||
private const int WIN_MAX_PATH = 260;
|
||||
private const string WIN_LONG_PATH_PREFIX = @"\\?\";
|
||||
internal static readonly bool IsWindows = System.Runtime.InteropServices.RuntimeInformation.IsOSPlatform(OSPlatform.Windows);
|
||||
internal static readonly bool IsLinux = System.Runtime.InteropServices.RuntimeInformation.IsOSPlatform(OSPlatform.Linux);
|
||||
internal static readonly bool IsOSX = System.Runtime.InteropServices.RuntimeInformation.IsOSPlatform(OSPlatform.OSX);
|
||||
|
||||
private const int MAX_PATH = 260;
|
||||
private const string LONG_PATH_PREFIX = @"\\?\";
|
||||
public string Path { get; }
|
||||
|
||||
public string Path { get; init; }
|
||||
public override string ToString() => Path;
|
||||
static LongPath()
|
||||
{
|
||||
if (IsWindows)
|
||||
{
|
||||
MaxPathLength = short.MaxValue;
|
||||
MaxDirectoryLength = MaxPathLength - 13;
|
||||
}
|
||||
else if (IsOSX)
|
||||
{
|
||||
MaxPathLength = 1024;
|
||||
MaxDirectoryLength = MaxPathLength - MaxFilenameLength;
|
||||
}
|
||||
else
|
||||
{
|
||||
MaxPathLength = 4096;
|
||||
MaxDirectoryLength = MaxPathLength - MaxFilenameLength;
|
||||
}
|
||||
}
|
||||
|
||||
private static readonly PlatformID PlatformID = Environment.OSVersion.Platform;
|
||||
private LongPath(string path)
|
||||
{
|
||||
if (IsWindows && path.Length > MaxPathLength)
|
||||
throw new System.IO.PathTooLongException($"Path exceeds {MaxPathLength} character limit. ({path})");
|
||||
if (!IsWindows && Encoding.UTF8.GetByteCount(path) > MaxPathLength)
|
||||
throw new System.IO.PathTooLongException($"Path exceeds {MaxPathLength} byte limit. ({path})");
|
||||
|
||||
Path = path;
|
||||
}
|
||||
|
||||
//Filename limits on NTFS and FAT filesystems are based on characters,
|
||||
//but on ext* filesystems they're based on bytes. The ext* filesystems
|
||||
//don't care about encoding, so how unicode characters are encoded is
|
||||
///a choice made by the linux kernel. As best as I can tell, pretty
|
||||
//much everyone uses UTF-8.
|
||||
public static int GetFilesystemStringLength(StringBuilder filename)
|
||||
=> LongPath.IsWindows ?
|
||||
filename.Length
|
||||
: Encoding.UTF8.GetByteCount(filename.ToString());
|
||||
|
||||
public static implicit operator LongPath(string path)
|
||||
{
|
||||
if (PlatformID is PlatformID.Unix) return new LongPath { Path = path };
|
||||
if (!IsWindows) return new LongPath(path);
|
||||
|
||||
if (path is null) return null;
|
||||
|
||||
@ -33,15 +70,15 @@ namespace FileManager
|
||||
//the name to an NT-style name, except when using the "\\?\" prefix
|
||||
path = path.Replace(System.IO.Path.AltDirectorySeparatorChar, System.IO.Path.DirectorySeparatorChar);
|
||||
|
||||
if (path.StartsWith(LONG_PATH_PREFIX))
|
||||
return new LongPath { Path = path };
|
||||
if (path.StartsWith(WIN_LONG_PATH_PREFIX))
|
||||
return new LongPath(path);
|
||||
else if ((path.Length > 2 && path[1] == ':') || path.StartsWith(@"UNC\"))
|
||||
return new LongPath { Path = LONG_PATH_PREFIX + path };
|
||||
return new LongPath(WIN_LONG_PATH_PREFIX + path);
|
||||
else if (path.StartsWith(@"\\"))
|
||||
//The "\\?\" prefix can also be used with paths constructed according to the
|
||||
//universal naming convention (UNC). To specify such a path using UNC, use
|
||||
//the "\\?\UNC\" prefix.
|
||||
return new LongPath { Path = LONG_PATH_PREFIX + @"UNC\" + path.Substring(2) };
|
||||
return new LongPath(WIN_LONG_PATH_PREFIX + @"UNC\" + path.Substring(2));
|
||||
else
|
||||
{
|
||||
//These prefixes are not used as part of the path itself. They indicate that
|
||||
@ -50,9 +87,9 @@ namespace FileManager
|
||||
//a period to represent the current directory, or double dots to represent the
|
||||
//parent directory. Because you cannot use the "\\?\" prefix with a relative
|
||||
//path, relative paths are always limited to a total of MAX_PATH characters.
|
||||
if (path.Length > MAX_PATH)
|
||||
if (path.Length > WIN_MAX_PATH)
|
||||
throw new System.IO.PathTooLongException();
|
||||
return new LongPath { Path = path };
|
||||
return new LongPath(path);
|
||||
}
|
||||
}
|
||||
|
||||
@ -63,7 +100,7 @@ namespace FileManager
|
||||
{
|
||||
get
|
||||
{
|
||||
if (PlatformID is PlatformID.Unix) return Path;
|
||||
if (!IsWindows) return Path;
|
||||
|
||||
//Short Path names are useful for navigating to the file in windows explorer,
|
||||
//which will not recognize paths longer than MAX_PATH. Short path names are not
|
||||
@ -103,7 +140,7 @@ namespace FileManager
|
||||
{
|
||||
get
|
||||
{
|
||||
if (PlatformID is PlatformID.Unix) return Path;
|
||||
if (!IsWindows) return Path;
|
||||
if (Path is null) return null;
|
||||
|
||||
StringBuilder longPathBuffer = new(MaxPathLength);
|
||||
@ -117,13 +154,16 @@ namespace FileManager
|
||||
{
|
||||
get
|
||||
{
|
||||
if (PlatformID is PlatformID.Unix) return Path;
|
||||
if (!IsWindows) return Path;
|
||||
return
|
||||
Path?.StartsWith(LONG_PATH_PREFIX) == true ? Path.Remove(0, LONG_PATH_PREFIX.Length)
|
||||
Path?.StartsWith(WIN_LONG_PATH_PREFIX) == true ? Path.Remove(0, WIN_LONG_PATH_PREFIX.Length)
|
||||
:Path;
|
||||
}
|
||||
}
|
||||
|
||||
public override string ToString() => Path;
|
||||
|
||||
|
||||
[DllImport("kernel32.dll", CharSet = CharSet.Unicode)]
|
||||
private static extern int GetShortPathName([MarshalAs(UnmanagedType.LPWStr)] string path, [MarshalAs(UnmanagedType.LPWStr)] StringBuilder shortPath, int shortPathLength);
|
||||
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
[Desktop Entry]
|
||||
Name=Libation
|
||||
Exec=Libation
|
||||
Exec=libation
|
||||
Icon=libation
|
||||
Comment=Liberate your Audiobooks
|
||||
Terminal=false
|
||||
|
||||
118
Source/targz2deb.sh
Normal file
118
Source/targz2deb.sh
Normal file
@ -0,0 +1,118 @@
|
||||
#!/bin/bash
|
||||
|
||||
FILE=$1
|
||||
|
||||
if [ -z "$FILE" ]
|
||||
then
|
||||
echo "This script must be called with a the Libation Linux bin zip file as an argument."
|
||||
exit
|
||||
fi
|
||||
|
||||
if [ ! -f "$FILE" ]
|
||||
then
|
||||
echo "The file \"$FILE\" does not exist."
|
||||
exit
|
||||
fi
|
||||
|
||||
# remove trailing ".tar.gz"
|
||||
FOLDER_MAIN=${FILE::-7}
|
||||
echo "Working dir: $FOLDER_MAIN"
|
||||
|
||||
if [[ -d "$FOLDER_MAIN" ]]
|
||||
then
|
||||
echo "$FOLDER_MAIN directory already exists, aborting."
|
||||
exit
|
||||
fi
|
||||
|
||||
FOLDER_EXEC="$FOLDER_MAIN/usr/lib/libation"
|
||||
echo "Exec dir: $FOLDER_EXEC"
|
||||
|
||||
FOLDER_ICON="$FOLDER_MAIN/usr/share/icons/hicolor/scalable/apps/"
|
||||
echo "Icon dir: $FOLDER_ICON"
|
||||
|
||||
FOLDER_DESKTOP="$FOLDER_MAIN/usr/share/applications"
|
||||
echo "Desktop dir: $FOLDER_DESKTOP"
|
||||
|
||||
FOLDER_DEBIAN="$FOLDER_MAIN/DEBIAN"
|
||||
echo "Debian dir: $FOLDER_DEBIAN"
|
||||
|
||||
mkdir -p "$FOLDER_EXEC"
|
||||
mkdir -p "$FOLDER_ICON"
|
||||
mkdir -p "$FOLDER_DESKTOP"
|
||||
mkdir -p "$FOLDER_DEBIAN"
|
||||
|
||||
echo "Extracting $FILE to $FOLDER_EXEC..."
|
||||
tar -xzf ${FILE} -C ${FOLDER_EXEC}
|
||||
|
||||
if [ $? -ne 0 ]
|
||||
then echo "Error extracting ${FILE}"
|
||||
exit
|
||||
fi
|
||||
|
||||
echo "Copying icon..."
|
||||
cp "$FOLDER_EXEC/glass-with-glow_256.svg" "$FOLDER_ICON/libation.svg"
|
||||
|
||||
echo "Copying desktop file..."
|
||||
cp "$FOLDER_EXEC/Libation.desktop" "$FOLDER_DESKTOP/Libation.desktop"
|
||||
|
||||
echo "Workaround for desktop file..."
|
||||
sed -i '/^Exec=Libation/c\Exec=/usr/bin/libation' "$FOLDER_DESKTOP/Libation.desktop"
|
||||
|
||||
echo "Creating pre-install file..."
|
||||
echo "#!/bin/bash
|
||||
|
||||
# Pre-install script, removes previous installation program files and sym links
|
||||
|
||||
echo \"Removing previously created symlinks...\"
|
||||
|
||||
rm /usr/bin/libation
|
||||
rm /usr/bin/Libation
|
||||
rm /usr/bin/hangover
|
||||
rm /usr/bin/Hangover
|
||||
rm /usr/bin/libationcli
|
||||
rm /usr/bin/LibationCli
|
||||
|
||||
echo \"Removing previously installed Libation files...\"
|
||||
|
||||
rm -r /usr/lib/libation
|
||||
rm -r /usr/lib/Libation
|
||||
|
||||
# making sure it won't stop installation
|
||||
exit 0
|
||||
" >> "$FOLDER_DEBIAN/preinst"
|
||||
|
||||
echo "Creating post-install file..."
|
||||
echo "#!/bin/bash
|
||||
|
||||
gtk-update-icon-cache -f /usr/share/icons/hicolor/
|
||||
|
||||
ln -s /usr/lib/libation/Libation /usr/bin/libation
|
||||
ln -s /usr/lib/libation/Hangover /usr/bin/hangover
|
||||
ln -s /usr/lib/libation/LibationCli /usr/bin/libationcli
|
||||
|
||||
# workaround until this file is moved to the user's home directory
|
||||
touch /usr/lib/libation/appsettings.json
|
||||
chmod 666 /usr/lib/libation/appsettings.json
|
||||
" >> "$FOLDER_DEBIAN/postinst"
|
||||
|
||||
echo "Creating control file..."
|
||||
echo "Package: Libation
|
||||
Version: 8.7.0
|
||||
Architecture: all
|
||||
Essential: no
|
||||
Priority: optional
|
||||
Depends: ffmpeg
|
||||
Maintainer: github.com/rmcrackan
|
||||
Description: liberate your audiobooks
|
||||
" >> "$FOLDER_DEBIAN/control"
|
||||
|
||||
echo "Changing permissions for pre- and post-install files..."
|
||||
chmod +x "$FOLDER_DEBIAN/preinst"
|
||||
chmod +x "$FOLDER_DEBIAN/postinst"
|
||||
|
||||
echo "Creating .deb file..."
|
||||
dpkg-deb --build $FOLDER_MAIN
|
||||
|
||||
rm -r "$FOLDER_MAIN"
|
||||
|
||||
echo "Done!"
|
||||
Loading…
x
Reference in New Issue
Block a user