diff --git a/Grayjay.ClientServer/Extensions.cs b/Grayjay.ClientServer/Extensions.cs
index 15c12376..ffc9e44b 100644
--- a/Grayjay.ClientServer/Extensions.cs
+++ b/Grayjay.ClientServer/Extensions.cs
@@ -196,6 +196,24 @@ public static string SanitizeFileName(this string fileName)
fileName = fileName.Replace(invalidChar, '_');
return fileName;
}
+
+ // Windows MAX_PATH is 260; reserve some room for the directory prefix.
+ private const int MaxFileNameLength = 200;
+ ///
+ /// Truncates a file name (after sanitization) so that the base name fits within
+ /// characters, preserving the extension.
+ ///
+ public static string TruncateFileName(this string fileName)
+ {
+ if (fileName.Length <= MaxFileNameLength)
+ return fileName;
+
+ string ext = Path.GetExtension(fileName); // e.g. ".mp4"
+ string baseName = Path.GetFileNameWithoutExtension(fileName);
+ int allowedBase = MaxFileNameLength - ext.Length;
+ if (allowedBase < 1) allowedBase = 1;
+ return baseName.Substring(0, Math.Min(baseName.Length, allowedBase)) + ext;
+ }
public static string SanitizeFileNameWithPath(this string path)
{
string dirName = Path.GetDirectoryName(path);
diff --git a/Grayjay.ClientServer/Models/Downloads/VideoDownload.cs b/Grayjay.ClientServer/Models/Downloads/VideoDownload.cs
index 80461395..c9c80da0 100644
--- a/Grayjay.ClientServer/Models/Downloads/VideoDownload.cs
+++ b/Grayjay.ClientServer/Models/Downloads/VideoDownload.cs
@@ -321,7 +321,7 @@ public async Task Download(ManagedHttpClient client, Action onProgress,
var representation = videoRepresentations?.FirstOrDefault();
var mimeType = representation?.MimeType ?? VideoSource.Container;
- VideoFileName = $"{VideoDetails.ID.Value} [{VideoSource.Width}x{VideoSource.Height}].{VideoHelper.VideoContainerToExtension(mimeType)}".SanitizeFileName();
+ VideoFileName = $"{VideoDetails.ID.Value} [{VideoSource.Width}x{VideoSource.Height}].{VideoHelper.VideoContainerToExtension(mimeType)}".SanitizeFileName().TruncateFileName();
VideoFilePath = Path.Combine(downloadDir, VideoFileName);
}
string audioDash = (AudioSource is DashManifestRawAudioSource dAudioSource) ? dAudioSource.Generate() : null;
@@ -331,12 +331,12 @@ public async Task Download(ManagedHttpClient client, Action onProgress,
var representation = audioRepresentations?.FirstOrDefault();
var mimeType = representation?.MimeType ?? AudioSource.Container;
- AudioFileName = $"{VideoDetails.ID.Value} [{AudioSource.Language}-{AudioSource.Bitrate}].{VideoHelper.AudioContainerToExtension(mimeType)}".SanitizeFileName();
+ AudioFileName = $"{VideoDetails.ID.Value} [{AudioSource.Language}-{AudioSource.Bitrate}].{VideoHelper.AudioContainerToExtension(mimeType)}".SanitizeFileName().TruncateFileName();
AudioFilePath = Path.Combine(downloadDir , AudioFileName);
}
if(SubtitleSourcetoUse != null)
{
- SubtitleFileName = $"{VideoDetails.ID.Value} [{SubtitleSourcetoUse.Name}].{VideoHelper.SubtitleContainerToExtension(SubtitleSourcetoUse.Format)}".SanitizeFileName();
+ SubtitleFileName = $"{VideoDetails.ID.Value} [{SubtitleSourcetoUse.Name}].{VideoHelper.SubtitleContainerToExtension(SubtitleSourcetoUse.Format)}".SanitizeFileName().TruncateFileName();
SubtitleFilePath = Path.Combine(downloadDir, SubtitleFileName);
}
var progressLock = new Object();