🐛 Fixes in drive video thumbnail
This commit is contained in:
@@ -182,11 +182,9 @@ public class FileController(
|
|||||||
.FirstOrDefaultAsync();
|
.FirstOrDefaultAsync();
|
||||||
if (file is null) return NotFound();
|
if (file is null) return NotFound();
|
||||||
|
|
||||||
|
await fs.DeleteFileDataAsync(file, force: true);
|
||||||
await fs.DeleteFileAsync(file);
|
await fs.DeleteFileAsync(file);
|
||||||
|
|
||||||
db.Files.Remove(file);
|
|
||||||
await db.SaveChangesAsync();
|
|
||||||
|
|
||||||
return NoContent();
|
return NoContent();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -1,3 +1,4 @@
|
|||||||
|
using System.Drawing;
|
||||||
using System.Globalization;
|
using System.Globalization;
|
||||||
using FFMpegCore;
|
using FFMpegCore;
|
||||||
using System.Security.Cryptography;
|
using System.Security.Cryptography;
|
||||||
@@ -169,26 +170,6 @@ public class FileService(
|
|||||||
IsEncrypted = !string.IsNullOrWhiteSpace(encryptPassword) && pool.PolicyConfig.AllowEncryption
|
IsEncrypted = !string.IsNullOrWhiteSpace(encryptPassword) && pool.PolicyConfig.AllowEncryption
|
||||||
};
|
};
|
||||||
|
|
||||||
// TODO: Enable the feature later
|
|
||||||
// var existingFile = await db.Files.AsNoTracking().FirstOrDefaultAsync(f => f.Hash == hash);
|
|
||||||
// file.StorageId = existingFile?.StorageId ?? file.Id;
|
|
||||||
//
|
|
||||||
// if (existingFile is not null)
|
|
||||||
// {
|
|
||||||
// file.FileMeta = existingFile.FileMeta;
|
|
||||||
// file.HasCompression = existingFile.HasCompression;
|
|
||||||
// file.SensitiveMarks = existingFile.SensitiveMarks;
|
|
||||||
// file.MimeType = existingFile.MimeType;
|
|
||||||
// file.UploadedAt = existingFile.UploadedAt;
|
|
||||||
// file.PoolId = existingFile.PoolId;
|
|
||||||
//
|
|
||||||
// db.Files.Add(file);
|
|
||||||
// await db.SaveChangesAsync();
|
|
||||||
// // Since the file content is a duplicate, we can delete the new upload and we are done.
|
|
||||||
// await stream.DisposeAsync();
|
|
||||||
// return file;
|
|
||||||
// }
|
|
||||||
|
|
||||||
// Extract metadata on the current thread for a faster initial response
|
// Extract metadata on the current thread for a faster initial response
|
||||||
if (!pool.PolicyConfig.NoMetadata)
|
if (!pool.PolicyConfig.NoMetadata)
|
||||||
await ExtractMetadataAsync(file, ogFilePath, stream);
|
await ExtractMetadataAsync(file, ogFilePath, stream);
|
||||||
@@ -272,6 +253,8 @@ public class FileService(
|
|||||||
var mediaInfo = await FFProbe.AnalyseAsync(filePath);
|
var mediaInfo = await FFProbe.AnalyseAsync(filePath);
|
||||||
file.FileMeta = new Dictionary<string, object?>
|
file.FileMeta = new Dictionary<string, object?>
|
||||||
{
|
{
|
||||||
|
["width"] = mediaInfo.PrimaryVideoStream?.Width,
|
||||||
|
["height"] = mediaInfo.PrimaryVideoStream?.Height,
|
||||||
["duration"] = mediaInfo.Duration.TotalSeconds,
|
["duration"] = mediaInfo.Duration.TotalSeconds,
|
||||||
["format_name"] = mediaInfo.Format.FormatName,
|
["format_name"] = mediaInfo.Format.FormatName,
|
||||||
["format_long_name"] = mediaInfo.Format.FormatLongName,
|
["format_long_name"] = mediaInfo.Format.FormatLongName,
|
||||||
@@ -284,7 +267,7 @@ public class FileService(
|
|||||||
{
|
{
|
||||||
s.AvgFrameRate, s.BitRate, s.CodecName, s.Duration, s.Height, s.Width, s.Language,
|
s.AvgFrameRate, s.BitRate, s.CodecName, s.Duration, s.Height, s.Width, s.Language,
|
||||||
s.PixelFormat, s.Rotation
|
s.PixelFormat, s.Rotation
|
||||||
}).ToList(),
|
}).Where(s => double.IsNormal(s.AvgFrameRate)).ToList(),
|
||||||
["audio_streams"] = mediaInfo.AudioStreams.Select(s => new
|
["audio_streams"] = mediaInfo.AudioStreams.Select(s => new
|
||||||
{
|
{
|
||||||
s.BitRate, s.Channels, s.ChannelLayout, s.CodecName, s.Duration, s.Language,
|
s.BitRate, s.Channels, s.ChannelLayout, s.CodecName, s.Duration, s.Language,
|
||||||
@@ -375,19 +358,24 @@ public class FileService(
|
|||||||
|
|
||||||
case "video":
|
case "video":
|
||||||
uploads.Add((originalFilePath, string.Empty, contentType, false));
|
uploads.Add((originalFilePath, string.Empty, contentType, false));
|
||||||
var thumbnailPath = Path.Join(Path.GetTempPath(), $"{TempFilePrefix}#{fileId}.thumbnail.webp");
|
|
||||||
|
var thumbnailPath = Path.Join(Path.GetTempPath(), $"{TempFilePrefix}#{fileId}.thumbnail.jpg");
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
var mediaInfo = await FFProbe.AnalyseAsync(originalFilePath);
|
await FFMpegArguments
|
||||||
var snapshotTime = mediaInfo.Duration > TimeSpan.FromSeconds(5)
|
.FromFileInput(originalFilePath, verifyExists: true)
|
||||||
? TimeSpan.FromSeconds(5)
|
.OutputToFile(thumbnailPath, overwrite: true, options => options
|
||||||
: TimeSpan.FromSeconds(1);
|
.Seek(TimeSpan.FromSeconds(0))
|
||||||
|
.WithFrameOutputCount(1)
|
||||||
await FFMpeg.SnapshotAsync(originalFilePath, thumbnailPath, captureTime: snapshotTime);
|
.WithCustomArgument("-q:v 2")
|
||||||
|
)
|
||||||
|
.NotifyOnOutput(line => logger.LogInformation("[FFmpeg] {Line}", line))
|
||||||
|
.NotifyOnError(line => logger.LogWarning("[FFmpeg] {Line}", line))
|
||||||
|
.ProcessAsynchronously();
|
||||||
|
|
||||||
if (File.Exists(thumbnailPath))
|
if (File.Exists(thumbnailPath))
|
||||||
{
|
{
|
||||||
uploads.Add((thumbnailPath, ".thumbnail", "image/webp", true));
|
uploads.Add((thumbnailPath, ".thumbnail", "image/jpeg", true));
|
||||||
hasThumbnail = true;
|
hasThumbnail = true;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
@@ -483,16 +471,27 @@ public class FileService(
|
|||||||
return Convert.ToHexString(hash).ToLowerInvariant();
|
return Convert.ToHexString(hash).ToLowerInvariant();
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task UploadFileToRemoteAsync(string storageId, Guid targetRemote, string filePath,
|
private async Task UploadFileToRemoteAsync(
|
||||||
string? suffix = null, string? contentType = null, bool selfDestruct = false)
|
string storageId,
|
||||||
|
Guid targetRemote,
|
||||||
|
string filePath,
|
||||||
|
string? suffix = null,
|
||||||
|
string? contentType = null,
|
||||||
|
bool selfDestruct = false
|
||||||
|
)
|
||||||
{
|
{
|
||||||
await using var fileStream = File.OpenRead(filePath);
|
await using var fileStream = File.OpenRead(filePath);
|
||||||
await UploadFileToRemoteAsync(storageId, targetRemote, fileStream, suffix, contentType);
|
await UploadFileToRemoteAsync(storageId, targetRemote, fileStream, suffix, contentType);
|
||||||
if (selfDestruct) File.Delete(filePath);
|
if (selfDestruct) File.Delete(filePath);
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task UploadFileToRemoteAsync(string storageId, Guid targetRemote, Stream stream,
|
private async Task UploadFileToRemoteAsync(
|
||||||
string? suffix = null, string? contentType = null)
|
string storageId,
|
||||||
|
Guid targetRemote,
|
||||||
|
Stream stream,
|
||||||
|
string? suffix = null,
|
||||||
|
string? contentType = null
|
||||||
|
)
|
||||||
{
|
{
|
||||||
var dest = await GetRemoteStorageConfig(targetRemote);
|
var dest = await GetRemoteStorageConfig(targetRemote);
|
||||||
if (dest is null)
|
if (dest is null)
|
||||||
@@ -564,7 +563,7 @@ public class FileService(
|
|||||||
await DeleteFileDataAsync(file);
|
await DeleteFileDataAsync(file);
|
||||||
}
|
}
|
||||||
|
|
||||||
private async Task DeleteFileDataAsync(CloudFile file, bool force = false)
|
public async Task DeleteFileDataAsync(CloudFile file, bool force = false)
|
||||||
{
|
{
|
||||||
if (file.StorageId is null) return;
|
if (file.StorageId is null) return;
|
||||||
if (!file.PoolId.HasValue) return;
|
if (!file.PoolId.HasValue) return;
|
||||||
|
Reference in New Issue
Block a user