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];
|
var fileNamePart = pathParts[^1];
|
||||||
pathParts.Remove(fileNamePart);
|
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());
|
LongPath directory = Path.Join(pathParts.Select(p => replaceFileName(p, paramReplacements, LongPath.MaxFilenameLength)).ToArray());
|
||||||
|
|
||||||
//If file already exists, GetValidFilename will append " (n)" to the filename.
|
//If file already exists, GetValidFilename will append " (n)" to the filename.
|
||||||
//This could cause the filename length to exceed MaxFilenameLength, so reduce
|
//This could cause the filename length to exceed MaxFilenameLength, so reduce
|
||||||
//allowable filename length by 5 chars, allowing for up to 99 duplicates.
|
//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)
|
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
|
//Remove 1 character from the end of the longest filename part until
|
||||||
//the total filename is less than max filename length
|
//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);
|
int maxLength = filenameParts.Max(p => p.Length);
|
||||||
var maxEntry = filenameParts.First(p => p.Length == maxLength);
|
var maxEntry = filenameParts.First(p => p.Length == maxLength);
|
||||||
|
|||||||
@ -6,11 +6,14 @@ using System.Text.RegularExpressions;
|
|||||||
using Dinah.Core;
|
using Dinah.Core;
|
||||||
using Polly;
|
using Polly;
|
||||||
using Polly.Retry;
|
using Polly.Retry;
|
||||||
|
using Dinah.Core.Collections.Generic;
|
||||||
|
|
||||||
namespace FileManager
|
namespace FileManager
|
||||||
{
|
{
|
||||||
public static class FileUtility
|
public static class FileUtility
|
||||||
{
|
{
|
||||||
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// "txt" => ".txt"
|
/// "txt" => ".txt"
|
||||||
/// <br />".txt" => ".txt"
|
/// <br />".txt" => ".txt"
|
||||||
@ -55,15 +58,15 @@ namespace FileManager
|
|||||||
|
|
||||||
// ensure uniqueness and check lengths
|
// ensure uniqueness and check lengths
|
||||||
var dir = Path.GetDirectoryName(path);
|
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 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 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);
|
fullfilename = removeInvalidWhitespace(fullfilename);
|
||||||
|
|
||||||
@ -71,7 +74,7 @@ namespace FileManager
|
|||||||
while (File.Exists(fullfilename) && !returnFirstExisting)
|
while (File.Exists(fullfilename) && !returnFirstExisting)
|
||||||
{
|
{
|
||||||
var increm = $" ({++i})";
|
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;
|
return fullfilename;
|
||||||
@ -129,6 +132,18 @@ namespace FileManager
|
|||||||
|
|
||||||
public static string RemoveLastCharacter(this string str) => string.IsNullOrEmpty(str) ? str : str[..^1];
|
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>
|
/// <summary>
|
||||||
/// Move file.
|
/// Move file.
|
||||||
/// <br/>- Ensure valid file name path: remove invalid chars, ensure uniqueness, enforce max file length
|
/// <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
|
//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 const int MaxFilenameLength = 255;
|
||||||
|
public static readonly int MaxDirectoryLength;
|
||||||
private const int MAX_PATH = 260;
|
public static readonly int MaxPathLength;
|
||||||
private const string LONG_PATH_PREFIX = @"\\?\";
|
private const int WIN_MAX_PATH = 260;
|
||||||
|
private const string WIN_LONG_PATH_PREFIX = @"\\?\";
|
||||||
public string Path { get; init; }
|
internal static readonly bool IsWindows = System.Runtime.InteropServices.RuntimeInformation.IsOSPlatform(OSPlatform.Windows);
|
||||||
public override string ToString() => Path;
|
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 static readonly PlatformID PlatformID = Environment.OSVersion.Platform;
|
|
||||||
|
|
||||||
|
|
||||||
|
public string Path { get; }
|
||||||
|
|
||||||
|
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 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)
|
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;
|
if (path is null) return null;
|
||||||
|
|
||||||
@ -33,15 +70,15 @@ namespace FileManager
|
|||||||
//the name to an NT-style name, except when using the "\\?\" prefix
|
//the name to an NT-style name, except when using the "\\?\" prefix
|
||||||
path = path.Replace(System.IO.Path.AltDirectorySeparatorChar, System.IO.Path.DirectorySeparatorChar);
|
path = path.Replace(System.IO.Path.AltDirectorySeparatorChar, System.IO.Path.DirectorySeparatorChar);
|
||||||
|
|
||||||
if (path.StartsWith(LONG_PATH_PREFIX))
|
if (path.StartsWith(WIN_LONG_PATH_PREFIX))
|
||||||
return new LongPath { Path = path };
|
return new LongPath(path);
|
||||||
else if ((path.Length > 2 && path[1] == ':') || path.StartsWith(@"UNC\"))
|
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(@"\\"))
|
else if (path.StartsWith(@"\\"))
|
||||||
//The "\\?\" prefix can also be used with paths constructed according to the
|
//The "\\?\" prefix can also be used with paths constructed according to the
|
||||||
//universal naming convention (UNC). To specify such a path using UNC, use
|
//universal naming convention (UNC). To specify such a path using UNC, use
|
||||||
//the "\\?\UNC\" prefix.
|
//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
|
else
|
||||||
{
|
{
|
||||||
//These prefixes are not used as part of the path itself. They indicate that
|
//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
|
//a period to represent the current directory, or double dots to represent the
|
||||||
//parent directory. Because you cannot use the "\\?\" prefix with a relative
|
//parent directory. Because you cannot use the "\\?\" prefix with a relative
|
||||||
//path, relative paths are always limited to a total of MAX_PATH characters.
|
//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();
|
throw new System.IO.PathTooLongException();
|
||||||
return new LongPath { Path = path };
|
return new LongPath(path);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -63,7 +100,7 @@ namespace FileManager
|
|||||||
{
|
{
|
||||||
get
|
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,
|
//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
|
//which will not recognize paths longer than MAX_PATH. Short path names are not
|
||||||
@ -103,7 +140,7 @@ namespace FileManager
|
|||||||
{
|
{
|
||||||
get
|
get
|
||||||
{
|
{
|
||||||
if (PlatformID is PlatformID.Unix) return Path;
|
if (!IsWindows) return Path;
|
||||||
if (Path is null) return null;
|
if (Path is null) return null;
|
||||||
|
|
||||||
StringBuilder longPathBuffer = new(MaxPathLength);
|
StringBuilder longPathBuffer = new(MaxPathLength);
|
||||||
@ -117,13 +154,16 @@ namespace FileManager
|
|||||||
{
|
{
|
||||||
get
|
get
|
||||||
{
|
{
|
||||||
if (PlatformID is PlatformID.Unix) return Path;
|
if (!IsWindows) return Path;
|
||||||
return
|
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;
|
:Path;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public override string ToString() => Path;
|
||||||
|
|
||||||
|
|
||||||
[DllImport("kernel32.dll", CharSet = CharSet.Unicode)]
|
[DllImport("kernel32.dll", CharSet = CharSet.Unicode)]
|
||||||
private static extern int GetShortPathName([MarshalAs(UnmanagedType.LPWStr)] string path, [MarshalAs(UnmanagedType.LPWStr)] StringBuilder shortPath, int shortPathLength);
|
private static extern int GetShortPathName([MarshalAs(UnmanagedType.LPWStr)] string path, [MarshalAs(UnmanagedType.LPWStr)] StringBuilder shortPath, int shortPathLength);
|
||||||
|
|
||||||
|
|||||||
@ -1,6 +1,6 @@
|
|||||||
[Desktop Entry]
|
[Desktop Entry]
|
||||||
Name=Libation
|
Name=Libation
|
||||||
Exec=Libation
|
Exec=libation
|
||||||
Icon=libation
|
Icon=libation
|
||||||
Comment=Liberate your Audiobooks
|
Comment=Liberate your Audiobooks
|
||||||
Terminal=false
|
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