From a0729a80841969bf2d46a31301acfa83e1eb95da Mon Sep 17 00:00:00 2001 From: SuhorukovAnton Date: Fri, 3 Jun 2022 10:41:05 +0300 Subject: [PATCH 01/23] thumbnail: first version add from google and dropbox --- .../LoginProviders/GoogleLoginProvider.cs | 2 +- config/appsettings.json | 2 +- .../ASC.Files/Core/Core/Thirdparty/Box/BoxFileDao.cs | 5 +++++ .../Core/Core/Thirdparty/Dropbox/DropboxFileDao.cs | 6 ++++++ .../Core/Thirdparty/Dropbox/DropboxProviderInfo.cs | 10 ++++++++++ .../Core/Core/Thirdparty/Dropbox/DropboxStorage.cs | 9 ++++++++- .../Core/Thirdparty/GoogleDrive/GoogleDriveFileDao.cs | 5 +++++ .../Thirdparty/GoogleDrive/GoogleDriveProviderInfo.cs | 6 ++++++ .../Core/Thirdparty/GoogleDrive/GoogleDriveStorage.cs | 9 ++++++++- .../Core/Core/Thirdparty/IThirdPartyProviderDao.cs | 5 ----- .../Core/Core/Thirdparty/OneDrive/OneDriveFileDao.cs | 5 +++++ .../Core/Thirdparty/ProviderDao/ProviderFileDao.cs | 7 +++++++ .../Core/Thirdparty/SharePoint/SharePointFileDao.cs | 5 +++++ .../Core/Core/Thirdparty/Sharpbox/SharpBoxFileDao.cs | 5 +++++ .../ASC.Files/Core/HttpHandlers/FileHandler.ashx.cs | 7 +++++-- 15 files changed, 77 insertions(+), 11 deletions(-) diff --git a/common/ASC.FederatedLogin/LoginProviders/GoogleLoginProvider.cs b/common/ASC.FederatedLogin/LoginProviders/GoogleLoginProvider.cs index 082d8e35bd..7bd5b40169 100644 --- a/common/ASC.FederatedLogin/LoginProviders/GoogleLoginProvider.cs +++ b/common/ASC.FederatedLogin/LoginProviders/GoogleLoginProvider.cs @@ -47,7 +47,7 @@ public class GoogleLoginProvider : BaseLoginProvider public static readonly string[] GoogleDriveExt = new[] { ".gdoc", ".gsheet", ".gslides", ".gdraw" }; public static readonly string GoogleDriveMimeTypeFolder = "application/vnd.google-apps.folder"; - public static readonly string FilesFields = "id,name,mimeType,parents,createdTime,modifiedTime,owners/displayName,lastModifyingUser/displayName,capabilities/canEdit,size"; + public static readonly string FilesFields = "id,name,mimeType,parents,createdTime,modifiedTime,owners/displayName,lastModifyingUser/displayName,capabilities/canEdit,size,thumbnailLink"; public static readonly string ProfileFields = "emailAddresses,genders,names"; private readonly RequestHelper _requestHelper; diff --git a/config/appsettings.json b/config/appsettings.json index 0eb4241bcd..7c93d24d52 100644 --- a/config/appsettings.json +++ b/config/appsettings.json @@ -70,7 +70,7 @@ "header": "" }, "url": { - "public": "http://localhost:8085/", + "public": "http://192.168.1.36:8085/", "internal": "", "portal": "" } diff --git a/products/ASC.Files/Core/Core/Thirdparty/Box/BoxFileDao.cs b/products/ASC.Files/Core/Core/Thirdparty/Box/BoxFileDao.cs index 44134faa9d..1a6da11f6b 100644 --- a/products/ASC.Files/Core/Core/Thirdparty/Box/BoxFileDao.cs +++ b/products/ASC.Files/Core/Core/Thirdparty/Box/BoxFileDao.cs @@ -629,5 +629,10 @@ internal class BoxFileDao : BoxDaoBase, IFileDao return Task.CompletedTask; } + + public Task GetThumbnailAsync(File file) + { + throw new NotImplementedException(); + } #endregion } diff --git a/products/ASC.Files/Core/Core/Thirdparty/Dropbox/DropboxFileDao.cs b/products/ASC.Files/Core/Core/Thirdparty/Dropbox/DropboxFileDao.cs index 4f0606d56d..fa0b10d500 100644 --- a/products/ASC.Files/Core/Core/Thirdparty/Dropbox/DropboxFileDao.cs +++ b/products/ASC.Files/Core/Core/Thirdparty/Dropbox/DropboxFileDao.cs @@ -185,6 +185,7 @@ internal class DropboxFileDao : DropboxDaoBase, IFileDao } //Get only files + var items = await GetDropboxItemsAsync(parentId, false).ConfigureAwait(false); var files = items.Select(item => ToFile(item.AsFile)); @@ -542,6 +543,11 @@ internal class DropboxFileDao : DropboxDaoBase, IFileDao return false; } + public async Task GetThumbnailAsync(File file) + { + return await ProviderInfo.GetThumbnailsAsync(_dropboxDaoSelector.ConvertId(file.Id)); + } + #region chunking private File RestoreIds(File file) diff --git a/products/ASC.Files/Core/Core/Thirdparty/Dropbox/DropboxProviderInfo.cs b/products/ASC.Files/Core/Core/Thirdparty/Dropbox/DropboxProviderInfo.cs index db876c0849..0dc7b000e2 100644 --- a/products/ASC.Files/Core/Core/Thirdparty/Dropbox/DropboxProviderInfo.cs +++ b/products/ASC.Files/Core/Core/Thirdparty/Dropbox/DropboxProviderInfo.cs @@ -127,6 +127,11 @@ internal class DropboxProviderInfo : IProviderInfo { return _dropboxProviderInfoHelper.CacheResetAsync(ID, dropboxPath, isFile); } + + internal Task GetThumbnailsAsync(string filePath) + { + return _dropboxProviderInfoHelper.GetThumbnailsAsync(Storage, filePath); + } } [Scope] @@ -271,4 +276,9 @@ public class DropboxProviderInfoHelper await _cacheNotify.PublishAsync(new DropboxCacheItem { IsFile = isFile ?? false, IsFileExists = isFile.HasValue, Key = key }, CacheNotifyAction.Remove).ConfigureAwait(false); } } + + internal Task GetThumbnailsAsync(DropboxStorage storage, string filePath) + { + return storage.GetThumbnailsAsync(filePath); + } } diff --git a/products/ASC.Files/Core/Core/Thirdparty/Dropbox/DropboxStorage.cs b/products/ASC.Files/Core/Core/Thirdparty/Dropbox/DropboxStorage.cs index 5d6ad4a7eb..23ae4c9117 100644 --- a/products/ASC.Files/Core/Core/Thirdparty/Dropbox/DropboxStorage.cs +++ b/products/ASC.Files/Core/Core/Thirdparty/Dropbox/DropboxStorage.cs @@ -135,10 +135,17 @@ internal class DropboxStorage : IDisposable public async Task> GetItemsAsync(string folderPath) { var data = await _dropboxClient.Files.ListFolderAsync(folderPath); - return new List(data.Entries); } + public async Task GetThumbnailsAsync(string filePath) + { + var path = new PathOrLink.Path(filePath); + var arg = new ThumbnailV2Arg(path); + var responce = await _dropboxClient.Files.GetThumbnailV2Async(arg); + return await responce.GetContentAsStreamAsync(); + } + public Task DownloadStreamAsync(string filePath, int offset = 0) { ArgumentNullOrEmptyException.ThrowIfNullOrEmpty(filePath); diff --git a/products/ASC.Files/Core/Core/Thirdparty/GoogleDrive/GoogleDriveFileDao.cs b/products/ASC.Files/Core/Core/Thirdparty/GoogleDrive/GoogleDriveFileDao.cs index 0d2a94c637..d2e6ae1ae3 100644 --- a/products/ASC.Files/Core/Core/Thirdparty/GoogleDrive/GoogleDriveFileDao.cs +++ b/products/ASC.Files/Core/Core/Thirdparty/GoogleDrive/GoogleDriveFileDao.cs @@ -701,5 +701,10 @@ internal class GoogleDriveFileDao : GoogleDriveDaoBase, IFileDao return Task.CompletedTask; } + + public async Task GetThumbnailAsync(File file) + { + return await ProviderInfo.GetThumbnail(MakeDriveId(_googleDriveDaoSelector.ConvertId(file.Id))); + } #endregion } diff --git a/products/ASC.Files/Core/Core/Thirdparty/GoogleDrive/GoogleDriveProviderInfo.cs b/products/ASC.Files/Core/Core/Thirdparty/GoogleDrive/GoogleDriveProviderInfo.cs index 69be6266bc..ed10dd4b04 100644 --- a/products/ASC.Files/Core/Core/Thirdparty/GoogleDrive/GoogleDriveProviderInfo.cs +++ b/products/ASC.Files/Core/Core/Thirdparty/GoogleDrive/GoogleDriveProviderInfo.cs @@ -156,6 +156,12 @@ internal class GoogleDriveProviderInfo : IProviderInfo { return _googleDriveProviderInfoHelper.CacheResetChildsAsync(ID, parentDriveId, childFolder); } + + internal async Task GetThumbnail(string fileId) + { + var storage = await StorageAsync; + return await storage.GetThumbnail(fileId); + } } [Scope(Additional = typeof(GoogleDriveProviderInfoExtention))] diff --git a/products/ASC.Files/Core/Core/Thirdparty/GoogleDrive/GoogleDriveStorage.cs b/products/ASC.Files/Core/Core/Thirdparty/GoogleDrive/GoogleDriveStorage.cs index 42943b7cd5..16fcbbf431 100644 --- a/products/ASC.Files/Core/Core/Thirdparty/GoogleDrive/GoogleDriveStorage.cs +++ b/products/ASC.Files/Core/Core/Thirdparty/GoogleDrive/GoogleDriveStorage.cs @@ -155,7 +155,6 @@ internal class GoogleDriveStorage : IDisposable try { var request = _driveService.Files.Get(entryId); - request.Fields = GoogleLoginProvider.FilesFields; return await request.ExecuteAsync(); @@ -170,6 +169,14 @@ internal class GoogleDriveStorage : IDisposable } } + public async Task GetThumbnail(string fileId) + { + var entry = await GetEntryAsync(fileId); + var httpClient = _driveService.HttpClient; + var response = await httpClient.GetAsync(entry.ThumbnailLink); + return await response.Content.ReadAsStreamAsync(); + } + public List GetEntries(string folderId, bool? folders = null) { var request = _driveService.Files.List(); diff --git a/products/ASC.Files/Core/Core/Thirdparty/IThirdPartyProviderDao.cs b/products/ASC.Files/Core/Core/Thirdparty/IThirdPartyProviderDao.cs index a602a1c5df..19d7e0aeb1 100644 --- a/products/ASC.Files/Core/Core/Thirdparty/IThirdPartyProviderDao.cs +++ b/products/ASC.Files/Core/Core/Thirdparty/IThirdPartyProviderDao.cs @@ -77,11 +77,6 @@ internal abstract class ThirdPartyProviderDao return Task.CompletedTask; } - public Task GetThumbnailAsync(File file) - { - return Task.FromResult(null); - } - public virtual Task GetFileStreamAsync(File file) { return null; diff --git a/products/ASC.Files/Core/Core/Thirdparty/OneDrive/OneDriveFileDao.cs b/products/ASC.Files/Core/Core/Thirdparty/OneDrive/OneDriveFileDao.cs index 1dac8d9221..e329738aad 100644 --- a/products/ASC.Files/Core/Core/Thirdparty/OneDrive/OneDriveFileDao.cs +++ b/products/ASC.Files/Core/Core/Thirdparty/OneDrive/OneDriveFileDao.cs @@ -701,5 +701,10 @@ internal class OneDriveFileDao : OneDriveDaoBase, IFileDao System.IO.File.Delete(uploadSession.GetItemOrDefault("TempPath")); } } + + public Task GetThumbnailAsync(File file) + { + throw new NotImplementedException(); + } #endregion } diff --git a/products/ASC.Files/Core/Core/Thirdparty/ProviderDao/ProviderFileDao.cs b/products/ASC.Files/Core/Core/Thirdparty/ProviderDao/ProviderFileDao.cs index 6d19b67787..71c9448b39 100644 --- a/products/ASC.Files/Core/Core/Thirdparty/ProviderDao/ProviderFileDao.cs +++ b/products/ASC.Files/Core/Core/Thirdparty/ProviderDao/ProviderFileDao.cs @@ -520,5 +520,12 @@ internal class ProviderFileDao : ProviderDaoBase, IFileDao return file; } + + public Task GetThumbnailAsync(File file) + { + var fileDao = GetFileDao(file); + return fileDao.GetThumbnailAsync(file); + } + #endregion } diff --git a/products/ASC.Files/Core/Core/Thirdparty/SharePoint/SharePointFileDao.cs b/products/ASC.Files/Core/Core/Thirdparty/SharePoint/SharePointFileDao.cs index cefa18c15c..83439ff069 100644 --- a/products/ASC.Files/Core/Core/Thirdparty/SharePoint/SharePointFileDao.cs +++ b/products/ASC.Files/Core/Core/Thirdparty/SharePoint/SharePointFileDao.cs @@ -475,4 +475,9 @@ internal class SharePointFileDao : SharePointDaoBase, IFileDao return file; } + + public Task GetThumbnailAsync(File file) + { + throw new NotImplementedException(); + } } diff --git a/products/ASC.Files/Core/Core/Thirdparty/Sharpbox/SharpBoxFileDao.cs b/products/ASC.Files/Core/Core/Thirdparty/Sharpbox/SharpBoxFileDao.cs index e4a4c7773a..9b61bf55ea 100644 --- a/products/ASC.Files/Core/Core/Thirdparty/Sharpbox/SharpBoxFileDao.cs +++ b/products/ASC.Files/Core/Core/Thirdparty/Sharpbox/SharpBoxFileDao.cs @@ -706,5 +706,10 @@ internal class SharpBoxFileDao : SharpBoxDaoBase, IFileDao return file; } + + public Task GetThumbnailAsync(File file) + { + throw new NotImplementedException(); + } #endregion } diff --git a/products/ASC.Files/Core/HttpHandlers/FileHandler.ashx.cs b/products/ASC.Files/Core/HttpHandlers/FileHandler.ashx.cs index c7116a077d..e32f2d5e11 100644 --- a/products/ASC.Files/Core/HttpHandlers/FileHandler.ashx.cs +++ b/products/ASC.Files/Core/HttpHandlers/FileHandler.ashx.cs @@ -979,7 +979,7 @@ public class FileHandlerService return; } - if (file.ThumbnailStatus != Thumbnail.Created) + if (file.ThumbnailStatus != Thumbnail.Created && id is int) { context.Response.StatusCode = (int)HttpStatusCode.NotFound; return; @@ -990,7 +990,10 @@ public class FileHandlerService using (var stream = await fileDao.GetThumbnailAsync(file)) { - context.Response.Headers.Add("Content-Length", stream.Length.ToString(CultureInfo.InvariantCulture)); + if (id is int) + { + context.Response.Headers.Add("Content-Length", stream.Length.ToString(CultureInfo.InvariantCulture)); + } await stream.CopyToAsync(context.Response.Body); } } From 720121f56e1d1c3340cdd4b415775ce72d8eb905 Mon Sep 17 00:00:00 2001 From: SuhorukovAnton Date: Mon, 6 Jun 2022 17:28:51 +0300 Subject: [PATCH 02/23] add google and onedrive --- .../Core/Core/Thirdparty/Box/BoxDaoBase.cs | 6 ++++++ .../Core/Core/Thirdparty/Box/BoxFileDao.cs | 10 +++++----- .../Core/Thirdparty/Box/BoxProviderInfo.cs | 11 +++++++++++ .../Core/Core/Thirdparty/Box/BoxStorage.cs | 5 +++++ .../Core/Thirdparty/Dropbox/DropboxStorage.cs | 4 +++- .../GoogleDrive/GoogleDriveFileDao.cs | 9 +++++---- .../Thirdparty/OneDrive/OneDriveDaoBase.cs | 6 ++++++ .../Thirdparty/OneDrive/OneDriveFileDao.cs | 10 +++++----- .../OneDrive/OneDriveProviderInfo.cs | 11 +++++++++++ .../Thirdparty/OneDrive/OneDriveStorage.cs | 18 ++++++++++++++++++ .../Thirdparty/Sharpbox/SharpBoxFileDao.cs | 10 +++++----- 11 files changed, 80 insertions(+), 20 deletions(-) diff --git a/products/ASC.Files/Core/Core/Thirdparty/Box/BoxDaoBase.cs b/products/ASC.Files/Core/Core/Thirdparty/Box/BoxDaoBase.cs index b5c190a97b..db2873e4e7 100644 --- a/products/ASC.Files/Core/Core/Thirdparty/Box/BoxDaoBase.cs +++ b/products/ASC.Files/Core/Core/Thirdparty/Box/BoxDaoBase.cs @@ -273,6 +273,12 @@ internal abstract class BoxDaoBase : ThirdPartyProviderDao return items; } + protected Task GetThumbnailAsync(string fileId) + { + var boxFileId = MakeBoxId(fileId); + return ProviderInfo.GetThumbnailAsync(boxFileId); + } + protected sealed class ErrorFolder : BoxFolder { public string Error { get; set; } diff --git a/products/ASC.Files/Core/Core/Thirdparty/Box/BoxFileDao.cs b/products/ASC.Files/Core/Core/Thirdparty/Box/BoxFileDao.cs index 1a6da11f6b..05a8bb4a53 100644 --- a/products/ASC.Files/Core/Core/Thirdparty/Box/BoxFileDao.cs +++ b/products/ASC.Files/Core/Core/Thirdparty/Box/BoxFileDao.cs @@ -545,6 +545,11 @@ internal class BoxFileDao : BoxDaoBase, IFileDao return false; } + public Task GetThumbnailAsync(File file) + { + return GetThumbnailAsync(_boxDaoSelector.ConvertId(file.Id)); + } + #region chunking private File RestoreIds(File file) @@ -629,10 +634,5 @@ internal class BoxFileDao : BoxDaoBase, IFileDao return Task.CompletedTask; } - - public Task GetThumbnailAsync(File file) - { - throw new NotImplementedException(); - } #endregion } diff --git a/products/ASC.Files/Core/Core/Thirdparty/Box/BoxProviderInfo.cs b/products/ASC.Files/Core/Core/Thirdparty/Box/BoxProviderInfo.cs index bdd3eb3419..c7f52f8805 100644 --- a/products/ASC.Files/Core/Core/Thirdparty/Box/BoxProviderInfo.cs +++ b/products/ASC.Files/Core/Core/Thirdparty/Box/BoxProviderInfo.cs @@ -145,6 +145,12 @@ internal class BoxProviderInfo : IProviderInfo { return _boxProviderInfoHelper.CacheResetAsync(BoxRootId, ID, boxPath, isFile); } + + internal async Task GetThumbnailAsync(string boxFileId) + { + var storage = await StorageAsync; + return await _boxProviderInfoHelper.GetThumbnailAsync(storage, boxFileId); + } } [Scope] @@ -330,4 +336,9 @@ public class BoxProviderInfoHelper await _cacheNotify.PublishAsync(new BoxCacheItem { IsFile = isFile ?? false, IsFileExists = isFile.HasValue, Key = key }, CacheNotifyAction.Remove).ConfigureAwait(false); } } + + internal async Task GetThumbnailAsync(BoxStorage storage, string boxFileId) + { + return await storage.GetThumbnailAsync(boxFileId).ConfigureAwait(false); + } } diff --git a/products/ASC.Files/Core/Core/Thirdparty/Box/BoxStorage.cs b/products/ASC.Files/Core/Core/Thirdparty/Box/BoxStorage.cs index dcaae2323e..852e83086b 100644 --- a/products/ASC.Files/Core/Core/Thirdparty/Box/BoxStorage.cs +++ b/products/ASC.Files/Core/Core/Thirdparty/Box/BoxStorage.cs @@ -270,4 +270,9 @@ internal class BoxStorage //todo: without chunked uploader: return Math.Min(max, MaxChunkedUploadFileSize); } + + public Task GetThumbnailAsync(string fileId) + { + return _boxClient.FilesManager.GetThumbnailAsync(fileId, 320, 320, 320, 320, extension: "jpg"); + } } diff --git a/products/ASC.Files/Core/Core/Thirdparty/Dropbox/DropboxStorage.cs b/products/ASC.Files/Core/Core/Thirdparty/Dropbox/DropboxStorage.cs index 23ae4c9117..3f8010d3a6 100644 --- a/products/ASC.Files/Core/Core/Thirdparty/Dropbox/DropboxStorage.cs +++ b/products/ASC.Files/Core/Core/Thirdparty/Dropbox/DropboxStorage.cs @@ -141,7 +141,9 @@ internal class DropboxStorage : IDisposable public async Task GetThumbnailsAsync(string filePath) { var path = new PathOrLink.Path(filePath); - var arg = new ThumbnailV2Arg(path); + var size = ThumbnailSize.W256h256.Instance; + var arg = new ThumbnailV2Arg(path, size: size); + var responce = await _dropboxClient.Files.GetThumbnailV2Async(arg); return await responce.GetContentAsStreamAsync(); } diff --git a/products/ASC.Files/Core/Core/Thirdparty/GoogleDrive/GoogleDriveFileDao.cs b/products/ASC.Files/Core/Core/Thirdparty/GoogleDrive/GoogleDriveFileDao.cs index d2e6ae1ae3..53e10634f5 100644 --- a/products/ASC.Files/Core/Core/Thirdparty/GoogleDrive/GoogleDriveFileDao.cs +++ b/products/ASC.Files/Core/Core/Thirdparty/GoogleDrive/GoogleDriveFileDao.cs @@ -547,6 +547,11 @@ internal class GoogleDriveFileDao : GoogleDriveDaoBase, IFileDao return false; } + public async Task GetThumbnailAsync(File file) + { + return await ProviderInfo.GetThumbnail(MakeDriveId(_googleDriveDaoSelector.ConvertId(file.Id))); + } + #region chunking private File RestoreIds(File file) @@ -702,9 +707,5 @@ internal class GoogleDriveFileDao : GoogleDriveDaoBase, IFileDao return Task.CompletedTask; } - public async Task GetThumbnailAsync(File file) - { - return await ProviderInfo.GetThumbnail(MakeDriveId(_googleDriveDaoSelector.ConvertId(file.Id))); - } #endregion } diff --git a/products/ASC.Files/Core/Core/Thirdparty/OneDrive/OneDriveDaoBase.cs b/products/ASC.Files/Core/Core/Thirdparty/OneDrive/OneDriveDaoBase.cs index d7dfff2980..150070985d 100644 --- a/products/ASC.Files/Core/Core/Thirdparty/OneDrive/OneDriveDaoBase.cs +++ b/products/ASC.Files/Core/Core/Thirdparty/OneDrive/OneDriveDaoBase.cs @@ -344,6 +344,12 @@ internal abstract class OneDriveDaoBase : ThirdPartyProviderDao GetThumbnailAsync(string fileId) + { + var oneDriveId = MakeOneDriveId(fileId); + return ProviderInfo.GetThumbnailAsync(oneDriveId); + } + private string MatchEvaluator(Match match) { var index = Convert.ToInt32(match.Groups[2].Value); diff --git a/products/ASC.Files/Core/Core/Thirdparty/OneDrive/OneDriveFileDao.cs b/products/ASC.Files/Core/Core/Thirdparty/OneDrive/OneDriveFileDao.cs index e329738aad..e1abf49ad8 100644 --- a/products/ASC.Files/Core/Core/Thirdparty/OneDrive/OneDriveFileDao.cs +++ b/products/ASC.Files/Core/Core/Thirdparty/OneDrive/OneDriveFileDao.cs @@ -556,6 +556,11 @@ internal class OneDriveFileDao : OneDriveDaoBase, IFileDao return false; } + public Task GetThumbnailAsync(File file) + { + return GetThumbnailAsync(_oneDriveDaoSelector.ConvertId(file.Id)); + } + #region chunking private File RestoreIds(File file) @@ -701,10 +706,5 @@ internal class OneDriveFileDao : OneDriveDaoBase, IFileDao System.IO.File.Delete(uploadSession.GetItemOrDefault("TempPath")); } } - - public Task GetThumbnailAsync(File file) - { - throw new NotImplementedException(); - } #endregion } diff --git a/products/ASC.Files/Core/Core/Thirdparty/OneDrive/OneDriveProviderInfo.cs b/products/ASC.Files/Core/Core/Thirdparty/OneDrive/OneDriveProviderInfo.cs index 96193363ce..a4f16c7b01 100644 --- a/products/ASC.Files/Core/Core/Thirdparty/OneDrive/OneDriveProviderInfo.cs +++ b/products/ASC.Files/Core/Core/Thirdparty/OneDrive/OneDriveProviderInfo.cs @@ -121,6 +121,12 @@ internal class OneDriveProviderInfo : IProviderInfo { return _oneDriveProviderInfoHelper.CacheResetAsync(ID, onedriveId); } + + internal async Task GetThumbnailAsync(string onedriveId) + { + var storage = await StorageAsync; + return await _oneDriveProviderInfoHelper.GetThumbnailAsync(storage, onedriveId); + } } [Scope(Additional = typeof(OneDriveProviderInfoExtention))] @@ -264,6 +270,11 @@ public class OneDriveProviderInfoHelper await _cacheNotify.PublishAsync(new OneDriveCacheItem { Key = key }, CacheNotifyAction.Remove).ConfigureAwait(false); } } + + internal async Task GetThumbnailAsync(OneDriveStorage storage, string onedriveId) + { + return await storage.GetThumbnailAsync(onedriveId).ConfigureAwait(false); + } } public static class OneDriveProviderInfoExtention { diff --git a/products/ASC.Files/Core/Core/Thirdparty/OneDrive/OneDriveStorage.cs b/products/ASC.Files/Core/Core/Thirdparty/OneDrive/OneDriveStorage.cs index c48801038a..71a60f5b7e 100644 --- a/products/ASC.Files/Core/Core/Thirdparty/OneDrive/OneDriveStorage.cs +++ b/products/ASC.Files/Core/Core/Thirdparty/OneDrive/OneDriveStorage.cs @@ -24,6 +24,8 @@ // content are licensed under the terms of the Creative Commons Attribution-ShareAlike 4.0 // International. See the License terms at http://creativecommons.org/licenses/by-sa/4.0/legalcode +using System.Net.Sockets; + using Folder = Microsoft.OneDrive.Sdk.Folder; namespace ASC.Files.Thirdparty.OneDrive; @@ -354,6 +356,22 @@ internal class OneDriveStorage var httpClient = _clientFactory.CreateClient(); using var response = await httpClient.SendAsync(request); } + + public async Task GetThumbnailAsync(string fileId) + { + var thumbnails = await OnedriveClient.Drive.Items[fileId].Thumbnails.Request().GetAsync(); + + var request = new HttpRequestMessage + { + RequestUri = new Uri(thumbnails[0].Medium.Url), + Method = HttpMethod.Get + }; + var httpClient = _clientFactory.CreateClient(); + using var response = await httpClient.SendAsync(request); + var bytes = await response.Content.ReadAsByteArrayAsync(); + var mem = new MemoryStream(bytes); + return new MemoryStream(bytes); + } } diff --git a/products/ASC.Files/Core/Core/Thirdparty/Sharpbox/SharpBoxFileDao.cs b/products/ASC.Files/Core/Core/Thirdparty/Sharpbox/SharpBoxFileDao.cs index 9b61bf55ea..d8097f46b9 100644 --- a/products/ASC.Files/Core/Core/Thirdparty/Sharpbox/SharpBoxFileDao.cs +++ b/products/ASC.Files/Core/Core/Thirdparty/Sharpbox/SharpBoxFileDao.cs @@ -561,6 +561,11 @@ internal class SharpBoxFileDao : SharpBoxDaoBase, IFileDao return false; } + public Task GetThumbnailAsync(File file) + { + throw new NotImplementedException(); + } + #region chunking public async Task> CreateUploadSessionAsync(File file, long contentLength) @@ -706,10 +711,5 @@ internal class SharpBoxFileDao : SharpBoxDaoBase, IFileDao return file; } - - public Task GetThumbnailAsync(File file) - { - throw new NotImplementedException(); - } #endregion } From d43693acb2b9d324ffc9b084aa663b7360ede250 Mon Sep 17 00:00:00 2001 From: SuhorukovAnton Date: Fri, 10 Jun 2022 16:06:32 +0300 Subject: [PATCH 03/23] get status Thumbnail.Created for thirdparty --- products/ASC.Files/Core/Core/Thirdparty/Box/BoxDaoBase.cs | 1 + .../ASC.Files/Core/Core/Thirdparty/Dropbox/DropboxDaoBase.cs | 1 + .../Core/Core/Thirdparty/GoogleDrive/GoogleDriveDaoBase.cs | 1 + .../ASC.Files/Core/Core/Thirdparty/OneDrive/OneDriveDaoBase.cs | 1 + 4 files changed, 4 insertions(+) diff --git a/products/ASC.Files/Core/Core/Thirdparty/Box/BoxDaoBase.cs b/products/ASC.Files/Core/Core/Thirdparty/Box/BoxDaoBase.cs index db2873e4e7..55200f9b55 100644 --- a/products/ASC.Files/Core/Core/Thirdparty/Box/BoxDaoBase.cs +++ b/products/ASC.Files/Core/Core/Thirdparty/Box/BoxDaoBase.cs @@ -191,6 +191,7 @@ internal abstract class BoxDaoBase : ThirdPartyProviderDao file.ModifiedOn = boxFile.ModifiedAt.HasValue ? _tenantUtil.DateTimeFromUtc(boxFile.ModifiedAt.Value.UtcDateTime) : default; file.NativeAccessor = boxFile; file.Title = MakeFileTitle(boxFile); + file.ThumbnailStatus = Thumbnail.Created; return file; } diff --git a/products/ASC.Files/Core/Core/Thirdparty/Dropbox/DropboxDaoBase.cs b/products/ASC.Files/Core/Core/Thirdparty/Dropbox/DropboxDaoBase.cs index 4d073f3017..3f88c66b63 100644 --- a/products/ASC.Files/Core/Core/Thirdparty/Dropbox/DropboxDaoBase.cs +++ b/products/ASC.Files/Core/Core/Thirdparty/Dropbox/DropboxDaoBase.cs @@ -195,6 +195,7 @@ internal abstract class DropboxDaoBase : ThirdPartyProviderDao Date: Tue, 14 Jun 2022 10:28:57 +0300 Subject: [PATCH 04/23] refactoring get ThumbnailFile --- .../Core/Core/Dao/Interfaces/IFileDao.cs | 2 + .../Core/Core/Dao/TeamlabDao/FileDao.cs | 6 ++ .../Core/Core/Thirdparty/Box/BoxDaoBase.cs | 6 -- .../Core/Core/Thirdparty/Box/BoxFileDao.cs | 8 ++- .../Core/Thirdparty/Dropbox/DropboxFileDao.cs | 9 ++- .../GoogleDrive/GoogleDriveFileDao.cs | 9 ++- .../Thirdparty/OneDrive/OneDriveDaoBase.cs | 6 -- .../Thirdparty/OneDrive/OneDriveFileDao.cs | 8 ++- .../Thirdparty/ProviderDao/ProviderFileDao.cs | 7 +++ .../SharePoint/SharePointFileDao.cs | 5 ++ .../Thirdparty/Sharpbox/SharpBoxFileDao.cs | 5 ++ .../Core/HttpHandlers/FileHandler.ashx.cs | 55 ++++++++++++++++--- 12 files changed, 99 insertions(+), 27 deletions(-) diff --git a/products/ASC.Files/Core/Core/Dao/Interfaces/IFileDao.cs b/products/ASC.Files/Core/Core/Dao/Interfaces/IFileDao.cs index 3123ed912c..2c37d4d7be 100644 --- a/products/ASC.Files/Core/Core/Dao/Interfaces/IFileDao.cs +++ b/products/ASC.Files/Core/Core/Dao/Interfaces/IFileDao.cs @@ -285,6 +285,8 @@ public interface IFileDao Task SaveThumbnailAsync(File file, Stream thumbnail); + Task GetThumbnailAsync(T fileId); + Task GetThumbnailAsync(File file); Task> GetFeedsAsync(int tenant, DateTime from, DateTime to); diff --git a/products/ASC.Files/Core/Core/Dao/TeamlabDao/FileDao.cs b/products/ASC.Files/Core/Core/Dao/TeamlabDao/FileDao.cs index 1710453058..9d4c903e91 100644 --- a/products/ASC.Files/Core/Core/Dao/TeamlabDao/FileDao.cs +++ b/products/ASC.Files/Core/Core/Dao/TeamlabDao/FileDao.cs @@ -1422,6 +1422,12 @@ internal class FileDao : AbstractDao, IFileDao await _globalStore.GetStore().SaveAsync(string.Empty, GetUniqFilePath(file, thumnailName), thumbnail, thumnailName); } + public async Task GetThumbnailAsync(int fileId) + { + var file = await GetFileAsync(fileId); + return await GetThumbnailAsync(file); + } + public async Task GetThumbnailAsync(File file) { var thumnailName = ThumbnailTitle + "." + _global.ThumbnailExtension; diff --git a/products/ASC.Files/Core/Core/Thirdparty/Box/BoxDaoBase.cs b/products/ASC.Files/Core/Core/Thirdparty/Box/BoxDaoBase.cs index 55200f9b55..a27c4a22ee 100644 --- a/products/ASC.Files/Core/Core/Thirdparty/Box/BoxDaoBase.cs +++ b/products/ASC.Files/Core/Core/Thirdparty/Box/BoxDaoBase.cs @@ -274,12 +274,6 @@ internal abstract class BoxDaoBase : ThirdPartyProviderDao return items; } - protected Task GetThumbnailAsync(string fileId) - { - var boxFileId = MakeBoxId(fileId); - return ProviderInfo.GetThumbnailAsync(boxFileId); - } - protected sealed class ErrorFolder : BoxFolder { public string Error { get; set; } diff --git a/products/ASC.Files/Core/Core/Thirdparty/Box/BoxFileDao.cs b/products/ASC.Files/Core/Core/Thirdparty/Box/BoxFileDao.cs index 05a8bb4a53..b217189930 100644 --- a/products/ASC.Files/Core/Core/Thirdparty/Box/BoxFileDao.cs +++ b/products/ASC.Files/Core/Core/Thirdparty/Box/BoxFileDao.cs @@ -547,7 +547,13 @@ internal class BoxFileDao : BoxDaoBase, IFileDao public Task GetThumbnailAsync(File file) { - return GetThumbnailAsync(_boxDaoSelector.ConvertId(file.Id)); + return GetThumbnailAsync(file.Id); + } + + public Task GetThumbnailAsync(string fileId) + { + var boxFileId = MakeBoxId(_boxDaoSelector.ConvertId(fileId)); + return ProviderInfo.GetThumbnailAsync(boxFileId); } #region chunking diff --git a/products/ASC.Files/Core/Core/Thirdparty/Dropbox/DropboxFileDao.cs b/products/ASC.Files/Core/Core/Thirdparty/Dropbox/DropboxFileDao.cs index fa0b10d500..17529cb5c8 100644 --- a/products/ASC.Files/Core/Core/Thirdparty/Dropbox/DropboxFileDao.cs +++ b/products/ASC.Files/Core/Core/Thirdparty/Dropbox/DropboxFileDao.cs @@ -543,9 +543,14 @@ internal class DropboxFileDao : DropboxDaoBase, IFileDao return false; } - public async Task GetThumbnailAsync(File file) + public Task GetThumbnailAsync(File file) { - return await ProviderInfo.GetThumbnailsAsync(_dropboxDaoSelector.ConvertId(file.Id)); + return GetThumbnailAsync(file.Id); + } + + public Task GetThumbnailAsync(string fileId) + { + return ProviderInfo.GetThumbnailsAsync(_dropboxDaoSelector.ConvertId(fileId)); } #region chunking diff --git a/products/ASC.Files/Core/Core/Thirdparty/GoogleDrive/GoogleDriveFileDao.cs b/products/ASC.Files/Core/Core/Thirdparty/GoogleDrive/GoogleDriveFileDao.cs index 53e10634f5..bd9bda41f4 100644 --- a/products/ASC.Files/Core/Core/Thirdparty/GoogleDrive/GoogleDriveFileDao.cs +++ b/products/ASC.Files/Core/Core/Thirdparty/GoogleDrive/GoogleDriveFileDao.cs @@ -547,9 +547,14 @@ internal class GoogleDriveFileDao : GoogleDriveDaoBase, IFileDao return false; } - public async Task GetThumbnailAsync(File file) + public Task GetThumbnailAsync(File file) { - return await ProviderInfo.GetThumbnail(MakeDriveId(_googleDriveDaoSelector.ConvertId(file.Id))); + return GetThumbnailAsync(file.Id); + } + + public Task GetThumbnailAsync(string fileId) + { + return ProviderInfo.GetThumbnail(MakeDriveId(_googleDriveDaoSelector.ConvertId(fileId))); } #region chunking diff --git a/products/ASC.Files/Core/Core/Thirdparty/OneDrive/OneDriveDaoBase.cs b/products/ASC.Files/Core/Core/Thirdparty/OneDrive/OneDriveDaoBase.cs index c11f3e4ee2..9e0b7882df 100644 --- a/products/ASC.Files/Core/Core/Thirdparty/OneDrive/OneDriveDaoBase.cs +++ b/products/ASC.Files/Core/Core/Thirdparty/OneDrive/OneDriveDaoBase.cs @@ -345,12 +345,6 @@ internal abstract class OneDriveDaoBase : ThirdPartyProviderDao GetThumbnailAsync(string fileId) - { - var oneDriveId = MakeOneDriveId(fileId); - return ProviderInfo.GetThumbnailAsync(oneDriveId); - } - private string MatchEvaluator(Match match) { var index = Convert.ToInt32(match.Groups[2].Value); diff --git a/products/ASC.Files/Core/Core/Thirdparty/OneDrive/OneDriveFileDao.cs b/products/ASC.Files/Core/Core/Thirdparty/OneDrive/OneDriveFileDao.cs index e1abf49ad8..9acc0e0a06 100644 --- a/products/ASC.Files/Core/Core/Thirdparty/OneDrive/OneDriveFileDao.cs +++ b/products/ASC.Files/Core/Core/Thirdparty/OneDrive/OneDriveFileDao.cs @@ -558,7 +558,13 @@ internal class OneDriveFileDao : OneDriveDaoBase, IFileDao public Task GetThumbnailAsync(File file) { - return GetThumbnailAsync(_oneDriveDaoSelector.ConvertId(file.Id)); + return GetThumbnailAsync(file.Id); + } + + public Task GetThumbnailAsync(string fileId) + { + var oneDriveId = MakeOneDriveId(_oneDriveDaoSelector.ConvertId(fileId)); + return ProviderInfo.GetThumbnailAsync(oneDriveId); } #region chunking diff --git a/products/ASC.Files/Core/Core/Thirdparty/ProviderDao/ProviderFileDao.cs b/products/ASC.Files/Core/Core/Thirdparty/ProviderDao/ProviderFileDao.cs index 71c9448b39..1e1c579685 100644 --- a/products/ASC.Files/Core/Core/Thirdparty/ProviderDao/ProviderFileDao.cs +++ b/products/ASC.Files/Core/Core/Thirdparty/ProviderDao/ProviderFileDao.cs @@ -521,6 +521,13 @@ internal class ProviderFileDao : ProviderDaoBase, IFileDao return file; } + public Task GetThumbnailAsync(string fileId) + { + var selector = GetSelector(fileId); + var fileDao = selector.GetFileDao(fileId); + return fileDao.GetThumbnailAsync(fileId); + } + public Task GetThumbnailAsync(File file) { var fileDao = GetFileDao(file); diff --git a/products/ASC.Files/Core/Core/Thirdparty/SharePoint/SharePointFileDao.cs b/products/ASC.Files/Core/Core/Thirdparty/SharePoint/SharePointFileDao.cs index 83439ff069..0ec6bec7a6 100644 --- a/products/ASC.Files/Core/Core/Thirdparty/SharePoint/SharePointFileDao.cs +++ b/products/ASC.Files/Core/Core/Thirdparty/SharePoint/SharePointFileDao.cs @@ -476,6 +476,11 @@ internal class SharePointFileDao : SharePointDaoBase, IFileDao return file; } + public Task GetThumbnailAsync(string fileid) + { + throw new NotImplementedException(); + } + public Task GetThumbnailAsync(File file) { throw new NotImplementedException(); diff --git a/products/ASC.Files/Core/Core/Thirdparty/Sharpbox/SharpBoxFileDao.cs b/products/ASC.Files/Core/Core/Thirdparty/Sharpbox/SharpBoxFileDao.cs index d8097f46b9..6273e6c90c 100644 --- a/products/ASC.Files/Core/Core/Thirdparty/Sharpbox/SharpBoxFileDao.cs +++ b/products/ASC.Files/Core/Core/Thirdparty/Sharpbox/SharpBoxFileDao.cs @@ -561,6 +561,11 @@ internal class SharpBoxFileDao : SharpBoxDaoBase, IFileDao return false; } + public Task GetThumbnailAsync(string fileid) + { + throw new NotImplementedException(); + } + public Task GetThumbnailAsync(File file) { throw new NotImplementedException(); diff --git a/products/ASC.Files/Core/HttpHandlers/FileHandler.ashx.cs b/products/ASC.Files/Core/HttpHandlers/FileHandler.ashx.cs index e32f2d5e11..0ec67b258d 100644 --- a/products/ASC.Files/Core/HttpHandlers/FileHandler.ashx.cs +++ b/products/ASC.Files/Core/HttpHandlers/FileHandler.ashx.cs @@ -947,15 +947,15 @@ public class FileHandlerService } else { - await ThumbnailFile(context, q.FirstOrDefault() ?? ""); + await ThumbnailFileFromThirdparty(context, q.FirstOrDefault() ?? ""); } } - private async Task ThumbnailFile(HttpContext context, T id) + private async Task ThumbnailFile(HttpContext context, int id) { try { - var fileDao = _daoFactory.GetFileDao(); + var fileDao = _daoFactory.GetFileDao(); var file = int.TryParse(context.Request.Query[FilesLinkUtility.Version], out var version) && version > 0 ? await fileDao.GetFileAsync(id, version) : await fileDao.GetFileAsync(id); @@ -979,7 +979,7 @@ public class FileHandlerService return; } - if (file.ThumbnailStatus != Thumbnail.Created && id is int) + if (file.ThumbnailStatus != Thumbnail.Created) { context.Response.StatusCode = (int)HttpStatusCode.NotFound; return; @@ -988,12 +988,49 @@ public class FileHandlerService context.Response.Headers.Add("Content-Disposition", ContentDispositionUtil.GetHeaderValue("." + _global.ThumbnailExtension)); context.Response.ContentType = MimeMapping.GetMimeMapping("." + _global.ThumbnailExtension); - using (var stream = await fileDao.GetThumbnailAsync(file)) + using (var stream = await fileDao.GetThumbnailAsync(id)) + { + context.Response.Headers.Add("Content-Length", stream.Length.ToString(CultureInfo.InvariantCulture)); + await stream.CopyToAsync(context.Response.Body); + } + } + catch (FileNotFoundException ex) + { + _logger.ErrorForUrl(context.Request.Url(), ex); + context.Response.StatusCode = (int)HttpStatusCode.NotFound; + await context.Response.WriteAsync(ex.Message); + return; + } + catch (Exception ex) + { + _logger.ErrorForUrl(context.Request.Url(), ex); + context.Response.StatusCode = (int)HttpStatusCode.InternalServerError; + await context.Response.WriteAsync(ex.Message); + return; + } + + try + { + await context.Response.Body.FlushAsync(); + await context.Response.CompleteAsync(); + } + catch (HttpException he) + { + _logger.ErrorThumbnail(he); + } + } + + private async Task ThumbnailFileFromThirdparty(HttpContext context, string id) + { + try + { + var fileDao = _daoFactory.GetFileDao(); + + context.Response.Headers.Add("Content-Disposition", ContentDispositionUtil.GetHeaderValue("." + _global.ThumbnailExtension)); + context.Response.ContentType = MimeMapping.GetMimeMapping("." + _global.ThumbnailExtension); + + using (var stream = await fileDao.GetThumbnailAsync(id)) { - if (id is int) - { - context.Response.Headers.Add("Content-Length", stream.Length.ToString(CultureInfo.InvariantCulture)); - } await stream.CopyToAsync(context.Response.Body); } } From c2b7f99f167b86f547b67d72250a56577822e959 Mon Sep 17 00:00:00 2001 From: SuhorukovAnton Date: Tue, 14 Jun 2022 10:45:52 +0300 Subject: [PATCH 05/23] refactoring get thumbnailFile --- .../Core/Thirdparty/Dropbox/DropboxStorage.cs | 17 +++++++++---- .../Thirdparty/OneDrive/OneDriveStorage.cs | 25 +++++++++++-------- 2 files changed, 27 insertions(+), 15 deletions(-) diff --git a/products/ASC.Files/Core/Core/Thirdparty/Dropbox/DropboxStorage.cs b/products/ASC.Files/Core/Core/Thirdparty/Dropbox/DropboxStorage.cs index 3f8010d3a6..a027950840 100644 --- a/products/ASC.Files/Core/Core/Thirdparty/Dropbox/DropboxStorage.cs +++ b/products/ASC.Files/Core/Core/Thirdparty/Dropbox/DropboxStorage.cs @@ -140,12 +140,19 @@ internal class DropboxStorage : IDisposable public async Task GetThumbnailsAsync(string filePath) { - var path = new PathOrLink.Path(filePath); - var size = ThumbnailSize.W256h256.Instance; - var arg = new ThumbnailV2Arg(path, size: size); + try + { + var path = new PathOrLink.Path(filePath); + var size = ThumbnailSize.W256h256.Instance; + var arg = new ThumbnailV2Arg(path, size: size); - var responce = await _dropboxClient.Files.GetThumbnailV2Async(arg); - return await responce.GetContentAsStreamAsync(); + var responce = await _dropboxClient.Files.GetThumbnailV2Async(arg); + return await responce.GetContentAsStreamAsync(); + } + catch + { + return null; + } } public Task DownloadStreamAsync(string filePath, int offset = 0) diff --git a/products/ASC.Files/Core/Core/Thirdparty/OneDrive/OneDriveStorage.cs b/products/ASC.Files/Core/Core/Thirdparty/OneDrive/OneDriveStorage.cs index 71a60f5b7e..ebe11303ac 100644 --- a/products/ASC.Files/Core/Core/Thirdparty/OneDrive/OneDriveStorage.cs +++ b/products/ASC.Files/Core/Core/Thirdparty/OneDrive/OneDriveStorage.cs @@ -360,17 +360,22 @@ internal class OneDriveStorage public async Task GetThumbnailAsync(string fileId) { var thumbnails = await OnedriveClient.Drive.Items[fileId].Thumbnails.Request().GetAsync(); - - var request = new HttpRequestMessage + if (thumbnails.Count > 0) { - RequestUri = new Uri(thumbnails[0].Medium.Url), - Method = HttpMethod.Get - }; - var httpClient = _clientFactory.CreateClient(); - using var response = await httpClient.SendAsync(request); - var bytes = await response.Content.ReadAsByteArrayAsync(); - var mem = new MemoryStream(bytes); - return new MemoryStream(bytes); + var request = new HttpRequestMessage + { + RequestUri = new Uri(thumbnails[0].Medium.Url), + Method = HttpMethod.Get + }; + var httpClient = _clientFactory.CreateClient(); + using var response = await httpClient.SendAsync(request); + var bytes = await response.Content.ReadAsByteArrayAsync(); + return new MemoryStream(bytes); + } + else + { + return null; + } } } From a875a35962345b3a027ad0a82760a31bfb0a70e9 Mon Sep 17 00:00:00 2001 From: SuhorukovAnton Date: Tue, 14 Jun 2022 11:45:57 +0300 Subject: [PATCH 06/23] fix --- config/appsettings.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/config/appsettings.json b/config/appsettings.json index 7c93d24d52..0eb4241bcd 100644 --- a/config/appsettings.json +++ b/config/appsettings.json @@ -70,7 +70,7 @@ "header": "" }, "url": { - "public": "http://192.168.1.36:8085/", + "public": "http://localhost:8085/", "internal": "", "portal": "" } From 0d1239af9559fff87ee20da0846aa0d92aac9c05 Mon Sep 17 00:00:00 2001 From: SuhorukovAnton Date: Thu, 16 Jun 2022 16:43:29 +0300 Subject: [PATCH 07/23] add thumbnails for video --- .../ASC.Files/Core/Log/FFmpegServiceLogger.cs | 5 +- .../Core/Services/FFmpegService/FFmpeg.cs | 110 ++++++++++++++++-- products/ASC.Files/Service/GlobalUsings.cs | 3 +- .../ASC.Files/Service/Thumbnail/Builder.cs | 43 ++++++- .../Service/Thumbnail/ThumbnailSettings.cs | 2 +- 5 files changed, 146 insertions(+), 17 deletions(-) diff --git a/products/ASC.Files/Core/Log/FFmpegServiceLogger.cs b/products/ASC.Files/Core/Log/FFmpegServiceLogger.cs index 96f26389dc..ce7115db53 100644 --- a/products/ASC.Files/Core/Log/FFmpegServiceLogger.cs +++ b/products/ASC.Files/Core/Log/FFmpegServiceLogger.cs @@ -30,6 +30,9 @@ internal static partial class FFmpegServiceLogger [LoggerMessage(Level = LogLevel.Error, Message = "FFmpeg/avconv was not found in PATH or 'files.ffmpeg' setting")] public static partial void ErrorFFmpeg(this ILogger logger); - [LoggerMessage(Level = LogLevel.Information, Message = "FFmpeg found in {path}")] + [LoggerMessage(Level = LogLevel.Error, Message = "File {file} not found")] + public static partial void ErrorFileNotFound(this ILogger logger, string file); + + [LoggerMessage(Level = LogLevel.Information, Message = "FFmpeg found in {path}")] public static partial void InformationFFmpegFoundIn(this ILogger logger, string path); } diff --git a/products/ASC.Files/Core/Services/FFmpegService/FFmpeg.cs b/products/ASC.Files/Core/Services/FFmpegService/FFmpeg.cs index 0e1d648b2f..f759a1156e 100644 --- a/products/ASC.Files/Core/Services/FFmpegService/FFmpeg.cs +++ b/products/ASC.Files/Core/Services/FFmpegService/FFmpeg.cs @@ -44,6 +44,14 @@ public class FFmpegService } } + private readonly List _convertableMedia; + private readonly List _fFmpegExecutables = new List() { "ffmpeg", "avconv" }; + private readonly string _fFmpegPath; + private readonly string _fFmpegArgs; + private readonly string _fFmpegThumbnailsArgs; + + private readonly ILogger _logger; + public bool IsConvertable(string extension) { return MustConvertable.Contains(extension.TrimStart('.')); @@ -86,6 +94,7 @@ public class FFmpegService _logger = logger; _fFmpegPath = configuration["files:ffmpeg:value"]; _fFmpegArgs = configuration["files:ffmpeg:args"] ?? "-i - -preset ultrafast -movflags frag_keyframe+empty_moov -f {0} -"; + _fFmpegThumbnailsArgs = configuration["files:ffmpeg:thumbnails:args"] ?? "-i - -vf \"thumbnail\" {0}"; _convertableMedia = (configuration.GetSection("files:ffmpeg:exts").Get() ?? Array.Empty()).ToList(); @@ -120,13 +129,6 @@ public class FFmpegService } } - private readonly List _convertableMedia; - private readonly List _fFmpegExecutables = new List() { "ffmpeg", "avconv" }; - private readonly string _fFmpegPath; - private readonly string _fFmpegArgs; - - private readonly ILogger _logger; - private ProcessStartInfo PrepareFFmpeg(string inputFormat) { if (!_convertableMedia.Contains(inputFormat.TrimStart('.'))) @@ -134,6 +136,15 @@ public class FFmpegService throw new ArgumentException("input format"); } + var startInfo = PrepareCommonFFmpeg(); + + startInfo.Arguments = string.Format(_fFmpegArgs, "mp4"); + + return startInfo; + } + + private ProcessStartInfo PrepareCommonFFmpeg() + { var startInfo = new ProcessStartInfo(); if (string.IsNullOrEmpty(_fFmpegPath)) @@ -143,19 +154,16 @@ public class FFmpegService } startInfo.FileName = _fFmpegPath; - startInfo.WorkingDirectory = Path.GetDirectoryName(_fFmpegPath); - startInfo.Arguments = string.Format(_fFmpegArgs, "mp4"); startInfo.UseShellExecute = false; startInfo.RedirectStandardOutput = true; startInfo.RedirectStandardInput = true; startInfo.RedirectStandardError = true; startInfo.CreateNoWindow = true; startInfo.WindowStyle = ProcessWindowStyle.Normal; - return startInfo; } - private static Task StreamCopyToAsync(Stream srcStream, Stream dstStream, bool closeSrc = false, bool closeDst = false) + private Task StreamCopyToAsync(Stream srcStream, Stream dstStream, bool closeSrc = false, bool closeDst = false) { ArgumentNullException.ThrowIfNull(srcStream); ArgumentNullException.ThrowIfNull(dstStream); @@ -163,7 +171,7 @@ public class FFmpegService return StreamCopyToAsyncInternal(srcStream, dstStream, closeSrc, closeDst); } - private static async Task StreamCopyToAsyncInternal(Stream srcStream, Stream dstStream, bool closeSrc, bool closeDst) + private async Task StreamCopyToAsyncInternal(Stream srcStream, Stream dstStream, bool closeSrc, bool closeDst) { const int bufs = 2048 * 4; @@ -202,4 +210,82 @@ public class FFmpegService _logger.Information(line); } } + + public async Task CreateThumbnail(Stream stream, string tempPath) + { + var startInfo = PrepareFFmpegForCreateThumbnail(tempPath); + + Process process; + using (process = new Process { StartInfo = startInfo }) + { + process.Start(); + + await StreamCopyForThumbnailAsync(stream, process.StandardInput.BaseStream, closeDst: true); + + await ProcessLog(process.StandardError.BaseStream); + + return GetFileStream(tempPath); + } + } + + private ProcessStartInfo PrepareFFmpegForCreateThumbnail(string tempFile) + { + var startInfo = PrepareCommonFFmpeg(); + + startInfo.Arguments = string.Format(_fFmpegThumbnailsArgs, tempFile); + + return startInfo; + } + + private Task StreamCopyForThumbnailAsync(Stream srcStream, Stream dstStream, bool closeSrc = false, bool closeDst = false) + { + ArgumentNullException.ThrowIfNull(srcStream); + ArgumentNullException.ThrowIfNull(dstStream); + + return StreamCopyForThumbnailAsyncInternal(srcStream, dstStream, closeSrc, closeDst); + } + + private async Task StreamCopyForThumbnailAsyncInternal(Stream srcStream, Stream dstStream, bool closeSrc, bool closeDst) + { + const int bufs = 2048 * 4; + + var buffer = new byte[bufs]; + int readed; + var total = 0; + + while ((readed = await srcStream.ReadAsync(buffer, 0, bufs)) > 0 && total < 9000000) // HACK: ffmpeg lock stream when total < 9000000 + { + await dstStream.WriteAsync(buffer, 0, readed); + await dstStream.FlushAsync(); + total += readed; + } + + if (closeSrc) + { + srcStream.Dispose(); + srcStream.Close(); + } + + if (closeDst) + { + await dstStream.FlushAsync(); + dstStream.Dispose(); + dstStream.Close(); + } + + return total; + } + + private Stream GetFileStream(string tempFile) + { + if (File.Exists(tempFile)) + { + return File.Open(tempFile, FileMode.Open); + } + else + { + _logger.ErrorFileNotFound(tempFile); + throw new IOException("file not found"); + } + } } diff --git a/products/ASC.Files/Service/GlobalUsings.cs b/products/ASC.Files/Service/GlobalUsings.cs index 0d33d3ad9a..484c7ab920 100644 --- a/products/ASC.Files/Service/GlobalUsings.cs +++ b/products/ASC.Files/Service/GlobalUsings.cs @@ -30,7 +30,7 @@ global using System.Reflection; global using ASC.Api.Core; global using ASC.Api.Core.Extensions; -global using ASC.Common; +global using ASC.Common; global using ASC.Common.Caching; global using ASC.Common.DependencyInjection; global using ASC.Common.Mapping; @@ -62,6 +62,7 @@ global using ASC.Web.Files.Classes; global using ASC.Web.Files.Core; global using ASC.Web.Files.Core.Search; global using ASC.Web.Files.Services.DocumentService; +global using ASC.Web.Files.Services.FFmpegService; global using Autofac; diff --git a/products/ASC.Files/Service/Thumbnail/Builder.cs b/products/ASC.Files/Service/Thumbnail/Builder.cs index 787853b696..477cd22a55 100644 --- a/products/ASC.Files/Service/Thumbnail/Builder.cs +++ b/products/ASC.Files/Service/Thumbnail/Builder.cs @@ -77,6 +77,8 @@ public class Builder private readonly Global _global; private readonly PathProvider _pathProvider; private readonly IHttpClientFactory _clientFactory; + private readonly FFmpegService _fFmpegService; + private readonly TempPath _tempPath; public Builder( ThumbnailSettings settings, @@ -87,7 +89,9 @@ public class Builder Global global, PathProvider pathProvider, ILoggerProvider log, - IHttpClientFactory clientFactory) + IHttpClientFactory clientFactory, + FFmpegService fFmpegService, + TempPath tempPath) { _config = settings; _tenantManager = tenantManager; @@ -98,6 +102,8 @@ public class Builder _pathProvider = pathProvider; _logger = log.CreateLogger("ASC.Files.ThumbnailBuilder"); _clientFactory = clientFactory; + _fFmpegService = fFmpegService; + _tempPath = tempPath; } internal async Task BuildThumbnail(FileData fileData) @@ -152,12 +158,18 @@ public class Builder if (!_config.FormatsArray.Contains(ext) || file.Encrypted || file.RootFolderType == FolderType.TRASH || file.ContentLength > _config.AvailableFileSize) { - file.ThumbnailStatus = ASC.Files.Core.Thumbnail.NotRequired; + file.ThumbnailStatus = Core.Thumbnail.NotRequired; await fileDao.SaveThumbnailAsync(file, null); return; } + if (IsVideo(file)) + { + await MakeThumbnailFromVideo(fileDao, file); + return; + } + if (IsImage(file)) { await CropImage(fileDao, file); @@ -178,6 +190,26 @@ public class Builder } } + private async Task MakeThumbnailFromVideo(IFileDao fileDao, File file) + { + var streamFile = await fileDao.GetFileStreamAsync(file); + + var tempPath = GetTempPath(); + var streamThumb = await _fFmpegService.CreateThumbnail(streamFile, tempPath); + + await Crop(fileDao, file, streamThumb); + + streamThumb.Dispose(); + streamThumb.Close(); + + File.Delete(tempPath); + } + + private string GetTempPath() + { + return Path.Combine(_tempPath.GetTempPath(), Path.ChangeExtension(Path.GetRandomFileName(), "jpg")); + } + private async Task MakeThumbnail(IFileDao fileDao, File file) { _logger.DebugMakeThumbnail1(file.Id.ToString()); @@ -299,6 +331,13 @@ public class Builder return FileUtility.ExtsImage.Contains(extension); } + private bool IsVideo(File file) + { + var extension = FileUtility.GetFileExtension(file.Title); + + return FileUtility.ExtsVideo.Contains(extension); + } + private async Task CropImage(IFileDao fileDao, File file) { _logger.DebugCropImage(file.Id.ToString()); diff --git a/products/ASC.Files/Service/Thumbnail/ThumbnailSettings.cs b/products/ASC.Files/Service/Thumbnail/ThumbnailSettings.cs index c4c4cbee41..31dabe7b23 100644 --- a/products/ASC.Files/Service/Thumbnail/ThumbnailSettings.cs +++ b/products/ASC.Files/Service/Thumbnail/ThumbnailSettings.cs @@ -65,7 +65,7 @@ public class ThumbnailSettings private string _formats; public string Formats { - get => _formats ?? ".pptx|.pptm|.ppt|.ppsx|.ppsm|.pps|.potx|.potm|.pot|.odp|.fodp|.otp|.gslides|.xlsx|.xlsm|.xls|.xltx|.xltm|.xlt|.ods|.fods|.ots|.gsheet|.csv|.docx|.docxf|.oform|.docm|.doc|.dotx|.dotm|.dot|.odt|.fodt|.ott|.gdoc|.txt|.rtf|.mht|.html|.htm|.fb2|.epub|.pdf|.djvu|.xps|.bmp|.jpeg|.jpg|.png|.gif|.tiff|.tif|.ico"; + get => _formats ?? ".pptx|.pptm|.ppt|.ppsx|.ppsm|.pps|.potx|.potm|.pot|.odp|.fodp|.otp|.gslides|.xlsx|.xlsm|.xls|.xltx|.xltm|.xlt|.ods|.fods|.ots|.gsheet|.csv|.docx|.docxf|.oform|.docm|.doc|.dotx|.dotm|.dot|.odt|.fodt|.ott|.gdoc|.txt|.rtf|.mht|.html|.htm|.fb2|.epub|.pdf|.djvu|.xps|.bmp|.jpeg|.jpg|.png|.gif|.tiff|.tif|.ico|.mp4"; set => _formats = value; } From 597db4684eba72b847a78ec630362d0b648a57fe Mon Sep 17 00:00:00 2001 From: SuhorukovAnton Date: Fri, 17 Jun 2022 13:17:53 +0300 Subject: [PATCH 08/23] refactoring --- .../Core/Core/Thirdparty/OneDrive/OneDriveStorage.cs | 2 -- .../Core/Core/Thirdparty/SharePoint/SharePointFileDao.cs | 4 ++-- .../Core/Core/Thirdparty/Sharpbox/SharpBoxFileDao.cs | 4 ++-- products/ASC.Files/Core/HttpHandlers/FileHandler.ashx.cs | 2 +- 4 files changed, 5 insertions(+), 7 deletions(-) diff --git a/products/ASC.Files/Core/Core/Thirdparty/OneDrive/OneDriveStorage.cs b/products/ASC.Files/Core/Core/Thirdparty/OneDrive/OneDriveStorage.cs index ebe11303ac..e09d1fb076 100644 --- a/products/ASC.Files/Core/Core/Thirdparty/OneDrive/OneDriveStorage.cs +++ b/products/ASC.Files/Core/Core/Thirdparty/OneDrive/OneDriveStorage.cs @@ -24,8 +24,6 @@ // content are licensed under the terms of the Creative Commons Attribution-ShareAlike 4.0 // International. See the License terms at http://creativecommons.org/licenses/by-sa/4.0/legalcode -using System.Net.Sockets; - using Folder = Microsoft.OneDrive.Sdk.Folder; namespace ASC.Files.Thirdparty.OneDrive; diff --git a/products/ASC.Files/Core/Core/Thirdparty/SharePoint/SharePointFileDao.cs b/products/ASC.Files/Core/Core/Thirdparty/SharePoint/SharePointFileDao.cs index 0ec6bec7a6..d52ad77be7 100644 --- a/products/ASC.Files/Core/Core/Thirdparty/SharePoint/SharePointFileDao.cs +++ b/products/ASC.Files/Core/Core/Thirdparty/SharePoint/SharePointFileDao.cs @@ -478,11 +478,11 @@ internal class SharePointFileDao : SharePointDaoBase, IFileDao public Task GetThumbnailAsync(string fileid) { - throw new NotImplementedException(); + return null; } public Task GetThumbnailAsync(File file) { - throw new NotImplementedException(); + return null; } } diff --git a/products/ASC.Files/Core/Core/Thirdparty/Sharpbox/SharpBoxFileDao.cs b/products/ASC.Files/Core/Core/Thirdparty/Sharpbox/SharpBoxFileDao.cs index 6273e6c90c..97e41cc7fc 100644 --- a/products/ASC.Files/Core/Core/Thirdparty/Sharpbox/SharpBoxFileDao.cs +++ b/products/ASC.Files/Core/Core/Thirdparty/Sharpbox/SharpBoxFileDao.cs @@ -563,12 +563,12 @@ internal class SharpBoxFileDao : SharpBoxDaoBase, IFileDao public Task GetThumbnailAsync(string fileid) { - throw new NotImplementedException(); + return null; } public Task GetThumbnailAsync(File file) { - throw new NotImplementedException(); + return null; } #region chunking diff --git a/products/ASC.Files/Core/HttpHandlers/FileHandler.ashx.cs b/products/ASC.Files/Core/HttpHandlers/FileHandler.ashx.cs index 0ec67b258d..b986ee5418 100644 --- a/products/ASC.Files/Core/HttpHandlers/FileHandler.ashx.cs +++ b/products/ASC.Files/Core/HttpHandlers/FileHandler.ashx.cs @@ -988,7 +988,7 @@ public class FileHandlerService context.Response.Headers.Add("Content-Disposition", ContentDispositionUtil.GetHeaderValue("." + _global.ThumbnailExtension)); context.Response.ContentType = MimeMapping.GetMimeMapping("." + _global.ThumbnailExtension); - using (var stream = await fileDao.GetThumbnailAsync(id)) + using (var stream = await fileDao.GetThumbnailAsync(file)) { context.Response.Headers.Add("Content-Length", stream.Length.ToString(CultureInfo.InvariantCulture)); await stream.CopyToAsync(context.Response.Body); From 494b2bc1e028aa317fb6868be0b5868f8e7b1031 Mon Sep 17 00:00:00 2001 From: SuhorukovAnton Date: Tue, 21 Jun 2022 10:53:05 +0300 Subject: [PATCH 09/23] merge --- products/ASC.Files/Core/Core/Thirdparty/Box/BoxFileDao.cs | 6 +++--- .../Core/Core/Thirdparty/Dropbox/DropboxFileDao.cs | 6 +++--- .../Core/Core/Thirdparty/Dropbox/DropboxProviderInfo.cs | 5 +++-- .../Core/Core/Thirdparty/Dropbox/DropboxStorage.cs | 2 ++ .../Core/Thirdparty/GoogleDrive/GoogleDriveFileDao.cs | 6 +++--- .../Core/Core/Thirdparty/OneDrive/OneDriveFileDao.cs | 6 +++--- .../Core/Core/Thirdparty/ProviderDao/ProviderFileDao.cs | 8 ++++---- .../Core/Core/Thirdparty/SharePoint/SharePointFileDao.cs | 4 ++-- .../Core/Core/Thirdparty/Sharpbox/SharpBoxFileDao.cs | 4 ++-- 9 files changed, 25 insertions(+), 22 deletions(-) diff --git a/products/ASC.Files/Core/Core/Thirdparty/Box/BoxFileDao.cs b/products/ASC.Files/Core/Core/Thirdparty/Box/BoxFileDao.cs index 36e1d96303..44a92507e3 100644 --- a/products/ASC.Files/Core/Core/Thirdparty/Box/BoxFileDao.cs +++ b/products/ASC.Files/Core/Core/Thirdparty/Box/BoxFileDao.cs @@ -550,12 +550,12 @@ internal class BoxFileDao : BoxDaoBase, IFileDao return false; } - public Task GetThumbnailAsync(File file) + public Task GetThumbnailAsync(File file, int width, int height) { - return GetThumbnailAsync(file.Id); + return GetThumbnailAsync(file.Id, width, height); } - public Task GetThumbnailAsync(string fileId) + public Task GetThumbnailAsync(string fileId, int width, int height) { var boxFileId = MakeBoxId(_boxDaoSelector.ConvertId(fileId)); return ProviderInfo.GetThumbnailAsync(boxFileId); diff --git a/products/ASC.Files/Core/Core/Thirdparty/Dropbox/DropboxFileDao.cs b/products/ASC.Files/Core/Core/Thirdparty/Dropbox/DropboxFileDao.cs index d8d28f9eef..22ad0c77d9 100644 --- a/products/ASC.Files/Core/Core/Thirdparty/Dropbox/DropboxFileDao.cs +++ b/products/ASC.Files/Core/Core/Thirdparty/Dropbox/DropboxFileDao.cs @@ -549,12 +549,12 @@ internal class DropboxFileDao : DropboxDaoBase, IFileDao return false; } - public Task GetThumbnailAsync(File file) + public Task GetThumbnailAsync(File file, int width, int height) { - return GetThumbnailAsync(file.Id); + return GetThumbnailAsync(file.Id, width, height); } - public Task GetThumbnailAsync(string fileId) + public Task GetThumbnailAsync(string fileId, int width, int height) { return ProviderInfo.GetThumbnailsAsync(_dropboxDaoSelector.ConvertId(fileId)); } diff --git a/products/ASC.Files/Core/Core/Thirdparty/Dropbox/DropboxProviderInfo.cs b/products/ASC.Files/Core/Core/Thirdparty/Dropbox/DropboxProviderInfo.cs index 386e139bb4..c5e0de150c 100644 --- a/products/ASC.Files/Core/Core/Thirdparty/Dropbox/DropboxProviderInfo.cs +++ b/products/ASC.Files/Core/Core/Thirdparty/Dropbox/DropboxProviderInfo.cs @@ -131,9 +131,10 @@ internal class DropboxProviderInfo : IProviderInfo return _dropboxProviderInfoHelper.CacheResetAsync(ID, dropboxPath, isFile); } - internal Task GetThumbnailsAsync(string filePath) + internal async Task GetThumbnailsAsync(string filePath) { - return _dropboxProviderInfoHelper.GetThumbnailsAsync(Storage, filePath); + var storage = await StorageAsync; + return await _dropboxProviderInfoHelper.GetThumbnailsAsync(storage, filePath); } } diff --git a/products/ASC.Files/Core/Core/Thirdparty/Dropbox/DropboxStorage.cs b/products/ASC.Files/Core/Core/Thirdparty/Dropbox/DropboxStorage.cs index a027950840..a44e038dbc 100644 --- a/products/ASC.Files/Core/Core/Thirdparty/Dropbox/DropboxStorage.cs +++ b/products/ASC.Files/Core/Core/Thirdparty/Dropbox/DropboxStorage.cs @@ -24,6 +24,8 @@ // content are licensed under the terms of the Creative Commons Attribution-ShareAlike 4.0 // International. See the License terms at http://creativecommons.org/licenses/by-sa/4.0/legalcode +using ThumbnailSize = Dropbox.Api.Files.ThumbnailSize; + namespace ASC.Files.Thirdparty.Dropbox; internal class DropboxStorage : IDisposable diff --git a/products/ASC.Files/Core/Core/Thirdparty/GoogleDrive/GoogleDriveFileDao.cs b/products/ASC.Files/Core/Core/Thirdparty/GoogleDrive/GoogleDriveFileDao.cs index 48f69228fb..d554478d83 100644 --- a/products/ASC.Files/Core/Core/Thirdparty/GoogleDrive/GoogleDriveFileDao.cs +++ b/products/ASC.Files/Core/Core/Thirdparty/GoogleDrive/GoogleDriveFileDao.cs @@ -552,12 +552,12 @@ internal class GoogleDriveFileDao : GoogleDriveDaoBase, IFileDao return false; } - public Task GetThumbnailAsync(File file) + public Task GetThumbnailAsync(File file, int width, int height) { - return GetThumbnailAsync(file.Id); + return GetThumbnailAsync(file.Id, width, height); } - public Task GetThumbnailAsync(string fileId) + public Task GetThumbnailAsync(string fileId, int width, int height) { return ProviderInfo.GetThumbnail(MakeDriveId(_googleDriveDaoSelector.ConvertId(fileId))); } diff --git a/products/ASC.Files/Core/Core/Thirdparty/OneDrive/OneDriveFileDao.cs b/products/ASC.Files/Core/Core/Thirdparty/OneDrive/OneDriveFileDao.cs index 9e634a936d..f761c8565f 100644 --- a/products/ASC.Files/Core/Core/Thirdparty/OneDrive/OneDriveFileDao.cs +++ b/products/ASC.Files/Core/Core/Thirdparty/OneDrive/OneDriveFileDao.cs @@ -561,12 +561,12 @@ internal class OneDriveFileDao : OneDriveDaoBase, IFileDao return false; } - public Task GetThumbnailAsync(File file) + public Task GetThumbnailAsync(File file, int width, int height) { - return GetThumbnailAsync(file.Id); + return GetThumbnailAsync(file.Id, width, height); } - public Task GetThumbnailAsync(string fileId) + public Task GetThumbnailAsync(string fileId, int width, int height) { var oneDriveId = MakeOneDriveId(_oneDriveDaoSelector.ConvertId(fileId)); return ProviderInfo.GetThumbnailAsync(oneDriveId); diff --git a/products/ASC.Files/Core/Core/Thirdparty/ProviderDao/ProviderFileDao.cs b/products/ASC.Files/Core/Core/Thirdparty/ProviderDao/ProviderFileDao.cs index eb0b7550fd..e11365c946 100644 --- a/products/ASC.Files/Core/Core/Thirdparty/ProviderDao/ProviderFileDao.cs +++ b/products/ASC.Files/Core/Core/Thirdparty/ProviderDao/ProviderFileDao.cs @@ -521,17 +521,17 @@ internal class ProviderFileDao : ProviderDaoBase, IFileDao return file; } - public Task GetThumbnailAsync(string fileId) + public Task GetThumbnailAsync(string fileId, int width, int height) { var selector = GetSelector(fileId); var fileDao = selector.GetFileDao(fileId); - return fileDao.GetThumbnailAsync(fileId); + return fileDao.GetThumbnailAsync(fileId, width, height); } - public Task GetThumbnailAsync(File file) + public Task GetThumbnailAsync(File file, int width, int height) { var fileDao = GetFileDao(file); - return fileDao.GetThumbnailAsync(file); + return fileDao.GetThumbnailAsync(file, width, height); } #endregion diff --git a/products/ASC.Files/Core/Core/Thirdparty/SharePoint/SharePointFileDao.cs b/products/ASC.Files/Core/Core/Thirdparty/SharePoint/SharePointFileDao.cs index d52ad77be7..23dfffca37 100644 --- a/products/ASC.Files/Core/Core/Thirdparty/SharePoint/SharePointFileDao.cs +++ b/products/ASC.Files/Core/Core/Thirdparty/SharePoint/SharePointFileDao.cs @@ -476,12 +476,12 @@ internal class SharePointFileDao : SharePointDaoBase, IFileDao return file; } - public Task GetThumbnailAsync(string fileid) + public Task GetThumbnailAsync(string fileid, int width, int height) { return null; } - public Task GetThumbnailAsync(File file) + public Task GetThumbnailAsync(File file, int width, int height) { return null; } diff --git a/products/ASC.Files/Core/Core/Thirdparty/Sharpbox/SharpBoxFileDao.cs b/products/ASC.Files/Core/Core/Thirdparty/Sharpbox/SharpBoxFileDao.cs index 16237e2455..a64eea7ed4 100644 --- a/products/ASC.Files/Core/Core/Thirdparty/Sharpbox/SharpBoxFileDao.cs +++ b/products/ASC.Files/Core/Core/Thirdparty/Sharpbox/SharpBoxFileDao.cs @@ -569,12 +569,12 @@ internal class SharpBoxFileDao : SharpBoxDaoBase, IFileDao return false; } - public Task GetThumbnailAsync(string fileid) + public Task GetThumbnailAsync(string fileid, int width, int height) { return null; } - public Task GetThumbnailAsync(File file) + public Task GetThumbnailAsync(File file, int width, int height) { return null; } From af252cc94937be1662cfad933c5ceb594a9ab1e0 Mon Sep 17 00:00:00 2001 From: pavelbannov Date: Thu, 23 Jun 2022 12:24:20 +0300 Subject: [PATCH 10/23] fix --- .../Core/Core/Thirdparty/IThirdPartyProviderDao.cs | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/products/ASC.Files/Core/Core/Thirdparty/IThirdPartyProviderDao.cs b/products/ASC.Files/Core/Core/Thirdparty/IThirdPartyProviderDao.cs index bd0d0b2612..bdf86caeb6 100644 --- a/products/ASC.Files/Core/Core/Thirdparty/IThirdPartyProviderDao.cs +++ b/products/ASC.Files/Core/Core/Thirdparty/IThirdPartyProviderDao.cs @@ -71,13 +71,17 @@ internal abstract class ThirdPartyProviderDao return Task.FromResult(false); } - public Task SaveThumbnailAsync(File file, Stream thumbnail, int width, int height) + public Task SaveThumbnailAsync(File file, Stream thumbnail, int width, int height) { //Do nothing return Task.CompletedTask; } public Task GetThumbnailAsync(File file, int width, int height) + { + return Task.FromResult(null); + } + public Task GetProperties(string fileId) { return Task.FromResult(null); @@ -402,7 +406,7 @@ internal abstract class ThirdPartyProviderDao : ThirdPartyProviderDao, IDispo var filtered = folders.Join(FilesDbContext.ThirdpartyIdMapping.ToAsyncEnumerable(), f => f.Id, m => m.Id, (folder, map) => new { folder, map.HashId }) .Join(FilesDbContext.TagLink.ToAsyncEnumerable(), r => r.HashId, t => t.EntryId, (result, tag) => new { result.folder, tag.TagId }) - .Join(FilesDbContext.Tag.ToAsyncEnumerable(), r => r.TagId, t => t.Id, (result, tagInfo) => new {result.folder, tagInfo.Name }) + .Join(FilesDbContext.Tag.ToAsyncEnumerable(), r => r.TagId, t => t.Id, (result, tagInfo) => new { result.folder, tagInfo.Name }) .Where(r => tagNames.Contains(r.Name)) .Select(r => r.folder); @@ -445,10 +449,10 @@ internal abstract class ThirdPartyProviderDao : ThirdPartyProviderDao, IDispo return Task.CompletedTask; } - public Task> GetSharesAsync(IEnumerable subjects) + public Task> GetSharesAsync(IEnumerable subjects) { List result = null; - return Task>.FromResult(result); + return Task>.FromResult(result); } public Task> GetSharesAsync(IEnumerable> entry) From 20deb4458a2bfce5ca3df484e260a3ef0b18bc86 Mon Sep 17 00:00:00 2001 From: SuhorukovAnton Date: Thu, 23 Jun 2022 15:18:15 +0300 Subject: [PATCH 11/23] thumbnails: adaptive size --- .../Core/Core/Thirdparty/Box/BoxFileDao.cs | 2 +- .../Core/Thirdparty/Box/BoxProviderInfo.cs | 8 ++++---- .../Core/Core/Thirdparty/Box/BoxStorage.cs | 4 ++-- .../Core/Thirdparty/Dropbox/DropboxFileDao.cs | 2 +- .../Thirdparty/Dropbox/DropboxProviderInfo.cs | 20 +++++++++++++------ .../Core/Thirdparty/Dropbox/DropboxStorage.cs | 17 ++++++++++++++-- .../GoogleDrive/GoogleDriveFileDao.cs | 2 +- .../GoogleDrive/GoogleDriveProviderInfo.cs | 4 ++-- .../GoogleDrive/GoogleDriveStorage.cs | 17 +++++++++++----- .../Core/Thirdparty/IThirdPartyProviderDao.cs | 5 ----- .../Thirdparty/OneDrive/OneDriveFileDao.cs | 2 +- .../OneDrive/OneDriveProviderInfo.cs | 8 ++++---- .../Thirdparty/OneDrive/OneDriveStorage.cs | 7 +++++-- .../Core/HttpHandlers/FileHandler.ashx.cs | 1 - 14 files changed, 62 insertions(+), 37 deletions(-) diff --git a/products/ASC.Files/Core/Core/Thirdparty/Box/BoxFileDao.cs b/products/ASC.Files/Core/Core/Thirdparty/Box/BoxFileDao.cs index 44a92507e3..972ec29a3c 100644 --- a/products/ASC.Files/Core/Core/Thirdparty/Box/BoxFileDao.cs +++ b/products/ASC.Files/Core/Core/Thirdparty/Box/BoxFileDao.cs @@ -558,7 +558,7 @@ internal class BoxFileDao : BoxDaoBase, IFileDao public Task GetThumbnailAsync(string fileId, int width, int height) { var boxFileId = MakeBoxId(_boxDaoSelector.ConvertId(fileId)); - return ProviderInfo.GetThumbnailAsync(boxFileId); + return ProviderInfo.GetThumbnailAsync(boxFileId, width, height); } #region chunking diff --git a/products/ASC.Files/Core/Core/Thirdparty/Box/BoxProviderInfo.cs b/products/ASC.Files/Core/Core/Thirdparty/Box/BoxProviderInfo.cs index b52059bc60..bbeee50489 100644 --- a/products/ASC.Files/Core/Core/Thirdparty/Box/BoxProviderInfo.cs +++ b/products/ASC.Files/Core/Core/Thirdparty/Box/BoxProviderInfo.cs @@ -148,10 +148,10 @@ internal class BoxProviderInfo : IProviderInfo return _boxProviderInfoHelper.CacheResetAsync(BoxRootId, ID, boxPath, isFile); } - internal async Task GetThumbnailAsync(string boxFileId) + internal async Task GetThumbnailAsync(string boxFileId, int width, int height) { var storage = await StorageAsync; - return await _boxProviderInfoHelper.GetThumbnailAsync(storage, boxFileId); + return await _boxProviderInfoHelper.GetThumbnailAsync(storage, boxFileId, width, height); } } @@ -339,8 +339,8 @@ public class BoxProviderInfoHelper } } - internal async Task GetThumbnailAsync(BoxStorage storage, string boxFileId) + internal async Task GetThumbnailAsync(BoxStorage storage, string boxFileId, int width, int height) { - return await storage.GetThumbnailAsync(boxFileId).ConfigureAwait(false); + return await storage.GetThumbnailAsync(boxFileId, width, height).ConfigureAwait(false); } } diff --git a/products/ASC.Files/Core/Core/Thirdparty/Box/BoxStorage.cs b/products/ASC.Files/Core/Core/Thirdparty/Box/BoxStorage.cs index 852e83086b..3fd55cf41d 100644 --- a/products/ASC.Files/Core/Core/Thirdparty/Box/BoxStorage.cs +++ b/products/ASC.Files/Core/Core/Thirdparty/Box/BoxStorage.cs @@ -271,8 +271,8 @@ internal class BoxStorage return Math.Min(max, MaxChunkedUploadFileSize); } - public Task GetThumbnailAsync(string fileId) + public Task GetThumbnailAsync(string fileId, int width, int height) { - return _boxClient.FilesManager.GetThumbnailAsync(fileId, 320, 320, 320, 320, extension: "jpg"); + return _boxClient.FilesManager.GetThumbnailAsync(fileId, width, height, extension: "jpg"); } } diff --git a/products/ASC.Files/Core/Core/Thirdparty/Dropbox/DropboxFileDao.cs b/products/ASC.Files/Core/Core/Thirdparty/Dropbox/DropboxFileDao.cs index 22ad0c77d9..4ef01b2863 100644 --- a/products/ASC.Files/Core/Core/Thirdparty/Dropbox/DropboxFileDao.cs +++ b/products/ASC.Files/Core/Core/Thirdparty/Dropbox/DropboxFileDao.cs @@ -556,7 +556,7 @@ internal class DropboxFileDao : DropboxDaoBase, IFileDao public Task GetThumbnailAsync(string fileId, int width, int height) { - return ProviderInfo.GetThumbnailsAsync(_dropboxDaoSelector.ConvertId(fileId)); + return ProviderInfo.GetThumbnailsAsync(_dropboxDaoSelector.ConvertId(fileId), width, height); } #region chunking diff --git a/products/ASC.Files/Core/Core/Thirdparty/Dropbox/DropboxProviderInfo.cs b/products/ASC.Files/Core/Core/Thirdparty/Dropbox/DropboxProviderInfo.cs index f5ee63bceb..9c86729b0f 100644 --- a/products/ASC.Files/Core/Core/Thirdparty/Dropbox/DropboxProviderInfo.cs +++ b/products/ASC.Files/Core/Core/Thirdparty/Dropbox/DropboxProviderInfo.cs @@ -133,14 +133,14 @@ internal class DropboxProviderInfo : IProviderInfo return _dropboxProviderInfoHelper.CacheResetAsync(ID, dropboxPath, isFile); } - internal async Task GetThumbnailsAsync(string filePath) + internal async Task GetThumbnailsAsync(string filePath, int width, int height) { var storage = await StorageAsync; - return await _dropboxProviderInfoHelper.GetThumbnailsAsync(storage, filePath); + return await _dropboxProviderInfoHelper.GetThumbnailsAsync(storage, filePath, width, height); } } -[Scope] +[Scope(Additional = typeof(DropboxStorageDisposableWrapperExtention))] internal class DropboxStorageDisposableWrapper : IDisposable { public DropboxStorage Storage { get; private set; } @@ -169,7 +169,7 @@ internal class DropboxStorageDisposableWrapper : IDisposable public async Task InternalCreateStorageAsync(OAuth20Token token, int id) { - var dropboxStorage = _serviceProvider.GetService(); + var dropboxStorage = _serviceProvider.GetRequiredService(); await CheckTokenAsync(token, id).ConfigureAwait(false); @@ -318,8 +318,16 @@ public class DropboxProviderInfoHelper } } - internal Task GetThumbnailsAsync(DropboxStorage storage, string filePath) + internal Task GetThumbnailsAsync(DropboxStorage storage, string filePath, int width, int height) { - return storage.GetThumbnailsAsync(filePath); + return storage.GetThumbnailsAsync(filePath, width, height); } } + +public static class DropboxStorageDisposableWrapperExtention +{ + public static void Register(DIHelper dIHelper) + { + dIHelper.TryAdd(); + } +} \ No newline at end of file diff --git a/products/ASC.Files/Core/Core/Thirdparty/Dropbox/DropboxStorage.cs b/products/ASC.Files/Core/Core/Thirdparty/Dropbox/DropboxStorage.cs index a44e038dbc..281cc1a339 100644 --- a/products/ASC.Files/Core/Core/Thirdparty/Dropbox/DropboxStorage.cs +++ b/products/ASC.Files/Core/Core/Thirdparty/Dropbox/DropboxStorage.cs @@ -28,6 +28,7 @@ using ThumbnailSize = Dropbox.Api.Files.ThumbnailSize; namespace ASC.Files.Thirdparty.Dropbox; +[Scope] internal class DropboxStorage : IDisposable { public bool IsOpened { get; private set; } @@ -140,12 +141,12 @@ internal class DropboxStorage : IDisposable return new List(data.Entries); } - public async Task GetThumbnailsAsync(string filePath) + public async Task GetThumbnailsAsync(string filePath, int width, int height) { try { var path = new PathOrLink.Path(filePath); - var size = ThumbnailSize.W256h256.Instance; + var size = Convert(width, height); var arg = new ThumbnailV2Arg(path, size: size); var responce = await _dropboxClient.Files.GetThumbnailV2Async(arg); @@ -157,6 +158,18 @@ internal class DropboxStorage : IDisposable } } + private ThumbnailSize Convert(int width, int height) + { + if (height > 320) + { + return ThumbnailSize.W480h320.Instance; + } + else + { + return ThumbnailSize.W256h256.Instance; + } + } + public Task DownloadStreamAsync(string filePath, int offset = 0) { ArgumentNullOrEmptyException.ThrowIfNullOrEmpty(filePath); diff --git a/products/ASC.Files/Core/Core/Thirdparty/GoogleDrive/GoogleDriveFileDao.cs b/products/ASC.Files/Core/Core/Thirdparty/GoogleDrive/GoogleDriveFileDao.cs index d554478d83..cc007e1d73 100644 --- a/products/ASC.Files/Core/Core/Thirdparty/GoogleDrive/GoogleDriveFileDao.cs +++ b/products/ASC.Files/Core/Core/Thirdparty/GoogleDrive/GoogleDriveFileDao.cs @@ -559,7 +559,7 @@ internal class GoogleDriveFileDao : GoogleDriveDaoBase, IFileDao public Task GetThumbnailAsync(string fileId, int width, int height) { - return ProviderInfo.GetThumbnail(MakeDriveId(_googleDriveDaoSelector.ConvertId(fileId))); + return ProviderInfo.GetThumbnail(MakeDriveId(_googleDriveDaoSelector.ConvertId(fileId)), width, height); } #region chunking diff --git a/products/ASC.Files/Core/Core/Thirdparty/GoogleDrive/GoogleDriveProviderInfo.cs b/products/ASC.Files/Core/Core/Thirdparty/GoogleDrive/GoogleDriveProviderInfo.cs index 6d5e2c4523..19b559495b 100644 --- a/products/ASC.Files/Core/Core/Thirdparty/GoogleDrive/GoogleDriveProviderInfo.cs +++ b/products/ASC.Files/Core/Core/Thirdparty/GoogleDrive/GoogleDriveProviderInfo.cs @@ -159,10 +159,10 @@ internal class GoogleDriveProviderInfo : IProviderInfo return _googleDriveProviderInfoHelper.CacheResetChildsAsync(ID, parentDriveId, childFolder); } - internal async Task GetThumbnail(string fileId) + internal async Task GetThumbnail(string fileId, int width, int height) { var storage = await StorageAsync; - return await storage.GetThumbnail(fileId); + return await storage.GetThumbnail(fileId, width, height); } } diff --git a/products/ASC.Files/Core/Core/Thirdparty/GoogleDrive/GoogleDriveStorage.cs b/products/ASC.Files/Core/Core/Thirdparty/GoogleDrive/GoogleDriveStorage.cs index 179bfba9cb..f89516da16 100644 --- a/products/ASC.Files/Core/Core/Thirdparty/GoogleDrive/GoogleDriveStorage.cs +++ b/products/ASC.Files/Core/Core/Thirdparty/GoogleDrive/GoogleDriveStorage.cs @@ -169,12 +169,19 @@ internal class GoogleDriveStorage : IDisposable } } - public async Task GetThumbnail(string fileId) + public async Task GetThumbnail(string fileId, int width, int height) { - var entry = await GetEntryAsync(fileId); - var httpClient = _driveService.HttpClient; - var response = await httpClient.GetAsync(entry.ThumbnailLink); - return await response.Content.ReadAsStreamAsync(); + try + { + var url = $"https://lh3.google.com/u/0/d/{fileId}=w{width}-h{height}-p-k-nu-iv1"; + var httpClient = _driveService.HttpClient; + var response = await httpClient.GetAsync(url); + return await response.Content.ReadAsStreamAsync(); + } + catch (Exception) + { + return null; + } } public List GetEntries(string folderId, bool? folders = null) diff --git a/products/ASC.Files/Core/Core/Thirdparty/IThirdPartyProviderDao.cs b/products/ASC.Files/Core/Core/Thirdparty/IThirdPartyProviderDao.cs index bdf86caeb6..1b5d573088 100644 --- a/products/ASC.Files/Core/Core/Thirdparty/IThirdPartyProviderDao.cs +++ b/products/ASC.Files/Core/Core/Thirdparty/IThirdPartyProviderDao.cs @@ -77,11 +77,6 @@ internal abstract class ThirdPartyProviderDao return Task.CompletedTask; } - public Task GetThumbnailAsync(File file, int width, int height) - { - return Task.FromResult(null); - } - public Task GetProperties(string fileId) { return Task.FromResult(null); diff --git a/products/ASC.Files/Core/Core/Thirdparty/OneDrive/OneDriveFileDao.cs b/products/ASC.Files/Core/Core/Thirdparty/OneDrive/OneDriveFileDao.cs index f761c8565f..61382da824 100644 --- a/products/ASC.Files/Core/Core/Thirdparty/OneDrive/OneDriveFileDao.cs +++ b/products/ASC.Files/Core/Core/Thirdparty/OneDrive/OneDriveFileDao.cs @@ -569,7 +569,7 @@ internal class OneDriveFileDao : OneDriveDaoBase, IFileDao public Task GetThumbnailAsync(string fileId, int width, int height) { var oneDriveId = MakeOneDriveId(_oneDriveDaoSelector.ConvertId(fileId)); - return ProviderInfo.GetThumbnailAsync(oneDriveId); + return ProviderInfo.GetThumbnailAsync(oneDriveId, width, height); } #region chunking diff --git a/products/ASC.Files/Core/Core/Thirdparty/OneDrive/OneDriveProviderInfo.cs b/products/ASC.Files/Core/Core/Thirdparty/OneDrive/OneDriveProviderInfo.cs index 6cf32378a5..6591d2ff81 100644 --- a/products/ASC.Files/Core/Core/Thirdparty/OneDrive/OneDriveProviderInfo.cs +++ b/products/ASC.Files/Core/Core/Thirdparty/OneDrive/OneDriveProviderInfo.cs @@ -124,10 +124,10 @@ internal class OneDriveProviderInfo : IProviderInfo return _oneDriveProviderInfoHelper.CacheResetAsync(ID, onedriveId); } - internal async Task GetThumbnailAsync(string onedriveId) + internal async Task GetThumbnailAsync(string onedriveId, int width, int height) { var storage = await StorageAsync; - return await _oneDriveProviderInfoHelper.GetThumbnailAsync(storage, onedriveId); + return await _oneDriveProviderInfoHelper.GetThumbnailAsync(storage, onedriveId, width, height); } } @@ -291,9 +291,9 @@ public class OneDriveProviderInfoHelper } } - internal async Task GetThumbnailAsync(OneDriveStorage storage, string onedriveId) + internal async Task GetThumbnailAsync(OneDriveStorage storage, string onedriveId, int width, int height) { - return await storage.GetThumbnailAsync(onedriveId).ConfigureAwait(false); + return await storage.GetThumbnailAsync(onedriveId, width, height).ConfigureAwait(false); } } public static class OneDriveProviderInfoExtention diff --git a/products/ASC.Files/Core/Core/Thirdparty/OneDrive/OneDriveStorage.cs b/products/ASC.Files/Core/Core/Thirdparty/OneDrive/OneDriveStorage.cs index e09d1fb076..fb5972ff2a 100644 --- a/products/ASC.Files/Core/Core/Thirdparty/OneDrive/OneDriveStorage.cs +++ b/products/ASC.Files/Core/Core/Thirdparty/OneDrive/OneDriveStorage.cs @@ -355,14 +355,17 @@ internal class OneDriveStorage using var response = await httpClient.SendAsync(request); } - public async Task GetThumbnailAsync(string fileId) + public async Task GetThumbnailAsync(string fileId, int width, int height) { var thumbnails = await OnedriveClient.Drive.Items[fileId].Thumbnails.Request().GetAsync(); if (thumbnails.Count > 0) { + var url = thumbnails[0].Medium.Url; + url = url.Substring(0, url.IndexOf("?width")); + url = url + $"?width={width}&height={height}&cropmode=none"; var request = new HttpRequestMessage { - RequestUri = new Uri(thumbnails[0].Medium.Url), + RequestUri = new Uri(url), Method = HttpMethod.Get }; var httpClient = _clientFactory.CreateClient(); diff --git a/products/ASC.Files/Core/HttpHandlers/FileHandler.ashx.cs b/products/ASC.Files/Core/HttpHandlers/FileHandler.ashx.cs index 5f4c588d79..3e49a3929a 100644 --- a/products/ASC.Files/Core/HttpHandlers/FileHandler.ashx.cs +++ b/products/ASC.Files/Core/HttpHandlers/FileHandler.ashx.cs @@ -1131,7 +1131,6 @@ public class FileHandlerService using (var stream = await fileDao.GetThumbnailAsync(id, width, height)) { - context.Response.Headers.Add("Content-Length", stream.Length.ToString(CultureInfo.InvariantCulture)); await stream.CopyToAsync(context.Response.Body); } } From 09612d377df27542b96c9b8a7e058e6d85c6463d Mon Sep 17 00:00:00 2001 From: SuhorukovAnton Date: Fri, 24 Jun 2022 11:53:12 +0300 Subject: [PATCH 12/23] box: add check can create thumbnail --- .../Core/Core/Thirdparty/Box/BoxStorage.cs | 19 +++++++++++++++++-- 1 file changed, 17 insertions(+), 2 deletions(-) diff --git a/products/ASC.Files/Core/Core/Thirdparty/Box/BoxStorage.cs b/products/ASC.Files/Core/Core/Thirdparty/Box/BoxStorage.cs index 3fd55cf41d..d37e581d73 100644 --- a/products/ASC.Files/Core/Core/Thirdparty/Box/BoxStorage.cs +++ b/products/ASC.Files/Core/Core/Thirdparty/Box/BoxStorage.cs @@ -271,8 +271,23 @@ internal class BoxStorage return Math.Min(max, MaxChunkedUploadFileSize); } - public Task GetThumbnailAsync(string fileId, int width, int height) + public async Task GetThumbnailAsync(string fileId, int width, int height) { - return _boxClient.FilesManager.GetThumbnailAsync(fileId, width, height, extension: "jpg"); + if (await CanGetThumbnailAsync(fileId)) + { + return await _boxClient.FilesManager.GetThumbnailAsync(fileId, width, height, extension: "jpg"); + } + else + { + return null; + } + } + + private async Task CanGetThumbnailAsync(string fileId) + { + var file = await GetFileAsync(fileId); + var extension = FileUtility.GetFileExtension(file.Name); + + return FileUtility.ExtsVideo.Contains(extension) || FileUtility.ExtsImage.Contains(extension); } } From d85c4dac295446a22b7cc7b294626229a0a94725 Mon Sep 17 00:00:00 2001 From: SuhorukovAnton Date: Fri, 24 Jun 2022 12:15:56 +0300 Subject: [PATCH 13/23] fix --- .../ASC.Files/Core/Core/Thirdparty/Dropbox/DropboxStorage.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/products/ASC.Files/Core/Core/Thirdparty/Dropbox/DropboxStorage.cs b/products/ASC.Files/Core/Core/Thirdparty/Dropbox/DropboxStorage.cs index 281cc1a339..74a0704ba5 100644 --- a/products/ASC.Files/Core/Core/Thirdparty/Dropbox/DropboxStorage.cs +++ b/products/ASC.Files/Core/Core/Thirdparty/Dropbox/DropboxStorage.cs @@ -160,7 +160,7 @@ internal class DropboxStorage : IDisposable private ThumbnailSize Convert(int width, int height) { - if (height > 320) + if (width > 368) { return ThumbnailSize.W480h320.Instance; } From fef096b0a5568ce25cb4358f128dc72a656050e2 Mon Sep 17 00:00:00 2001 From: pavelbannov Date: Fri, 24 Jun 2022 16:22:52 +0300 Subject: [PATCH 14/23] fix generating thumbnails for video --- common/ASC.Common/Data/TempPath.cs | 11 +- common/ASC.Common/Data/TempStream.cs | 9 +- .../Core/Core/Thirdparty/Box/BoxFileDao.cs | 7 +- .../Core/Thirdparty/Dropbox/DropboxFileDao.cs | 7 +- .../GoogleDrive/GoogleDriveFileDao.cs | 6 +- .../Core/Thirdparty/IThirdPartyProviderDao.cs | 10 ++ .../Thirdparty/OneDrive/OneDriveFileDao.cs | 7 +- .../Thirdparty/ProviderDao/ProviderFileDao.cs | 6 +- .../SharePoint/SharePointFileDao.cs | 10 -- .../Thirdparty/Sharpbox/SharpBoxFileDao.cs | 10 -- .../Core/Services/FFmpegService/FFmpeg.cs | 114 +----------------- .../ASC.Files/Service/Thumbnail/Builder.cs | 49 ++++---- 12 files changed, 66 insertions(+), 180 deletions(-) diff --git a/common/ASC.Common/Data/TempPath.cs b/common/ASC.Common/Data/TempPath.cs index a0d5bec57f..6159197821 100644 --- a/common/ASC.Common/Data/TempPath.cs +++ b/common/ASC.Common/Data/TempPath.cs @@ -31,7 +31,7 @@ public class TempPath { private readonly string _tempFolder; - public TempPath(IConfiguration configuration) + public TempPath(IHostEnvironment hostEnvironment, IConfiguration configuration) { var rootFolder = AppContext.BaseDirectory; if (string.IsNullOrEmpty(rootFolder)) @@ -39,7 +39,7 @@ public class TempPath rootFolder = Assembly.GetEntryAssembly().Location; } - _tempFolder = configuration["temp"] ?? Path.Combine("..", "Data", "temp"); + _tempFolder = configuration["web:temp"] ?? CrossPlatform.PathCombine(hostEnvironment.ContentRootPath, "temp"); if (!Path.IsPathRooted(_tempFolder)) { _tempFolder = Path.GetFullPath(Path.Combine(rootFolder, _tempFolder)); @@ -56,7 +56,7 @@ public class TempPath return _tempFolder; } - public string GetTempFileName() + public string GetTempFileName(string ext = "") { FileStream f = null; string path; @@ -66,6 +66,11 @@ public class TempPath { path = Path.Combine(_tempFolder, Path.GetRandomFileName()); + if (!string.IsNullOrEmpty(ext)) + { + path = Path.ChangeExtension(path, ext); + } + try { using (f = new FileStream(path, FileMode.CreateNew, FileAccess.ReadWrite, FileShare.Read)) diff --git a/common/ASC.Common/Data/TempStream.cs b/common/ASC.Common/Data/TempStream.cs index 5d1e7e5811..cc809cdc0b 100644 --- a/common/ASC.Common/Data/TempStream.cs +++ b/common/ASC.Common/Data/TempStream.cs @@ -54,7 +54,12 @@ public class TempStream public Stream Create() { - return new FileStream(_tempPath.GetTempFileName(), FileMode.OpenOrCreate, - FileAccess.ReadWrite, FileShare.Read, 4096, FileOptions.DeleteOnClose); + return Create(out _); + } + + public Stream Create(out string path, string ext = "") + { + path = _tempPath.GetTempFileName(ext); + return new FileStream(path, FileMode.OpenOrCreate, FileAccess.ReadWrite, FileShare.Read, 4096, FileOptions.DeleteOnClose); } } \ No newline at end of file diff --git a/products/ASC.Files/Core/Core/Thirdparty/Box/BoxFileDao.cs b/products/ASC.Files/Core/Core/Thirdparty/Box/BoxFileDao.cs index 972ec29a3c..5a2c4d9245 100644 --- a/products/ASC.Files/Core/Core/Thirdparty/Box/BoxFileDao.cs +++ b/products/ASC.Files/Core/Core/Thirdparty/Box/BoxFileDao.cs @@ -550,12 +550,7 @@ internal class BoxFileDao : BoxDaoBase, IFileDao return false; } - public Task GetThumbnailAsync(File file, int width, int height) - { - return GetThumbnailAsync(file.Id, width, height); - } - - public Task GetThumbnailAsync(string fileId, int width, int height) + public override Task GetThumbnailAsync(string fileId, int width, int height) { var boxFileId = MakeBoxId(_boxDaoSelector.ConvertId(fileId)); return ProviderInfo.GetThumbnailAsync(boxFileId, width, height); diff --git a/products/ASC.Files/Core/Core/Thirdparty/Dropbox/DropboxFileDao.cs b/products/ASC.Files/Core/Core/Thirdparty/Dropbox/DropboxFileDao.cs index 4ef01b2863..7c6be8afab 100644 --- a/products/ASC.Files/Core/Core/Thirdparty/Dropbox/DropboxFileDao.cs +++ b/products/ASC.Files/Core/Core/Thirdparty/Dropbox/DropboxFileDao.cs @@ -549,12 +549,7 @@ internal class DropboxFileDao : DropboxDaoBase, IFileDao return false; } - public Task GetThumbnailAsync(File file, int width, int height) - { - return GetThumbnailAsync(file.Id, width, height); - } - - public Task GetThumbnailAsync(string fileId, int width, int height) + public override Task GetThumbnailAsync(string fileId, int width, int height) { return ProviderInfo.GetThumbnailsAsync(_dropboxDaoSelector.ConvertId(fileId), width, height); } diff --git a/products/ASC.Files/Core/Core/Thirdparty/GoogleDrive/GoogleDriveFileDao.cs b/products/ASC.Files/Core/Core/Thirdparty/GoogleDrive/GoogleDriveFileDao.cs index cc007e1d73..3215c10289 100644 --- a/products/ASC.Files/Core/Core/Thirdparty/GoogleDrive/GoogleDriveFileDao.cs +++ b/products/ASC.Files/Core/Core/Thirdparty/GoogleDrive/GoogleDriveFileDao.cs @@ -552,12 +552,8 @@ internal class GoogleDriveFileDao : GoogleDriveDaoBase, IFileDao return false; } - public Task GetThumbnailAsync(File file, int width, int height) - { - return GetThumbnailAsync(file.Id, width, height); - } - public Task GetThumbnailAsync(string fileId, int width, int height) + public override Task GetThumbnailAsync(string fileId, int width, int height) { return ProviderInfo.GetThumbnail(MakeDriveId(_googleDriveDaoSelector.ConvertId(fileId)), width, height); } diff --git a/products/ASC.Files/Core/Core/Thirdparty/IThirdPartyProviderDao.cs b/products/ASC.Files/Core/Core/Thirdparty/IThirdPartyProviderDao.cs index 1b5d573088..e2bdbfa20a 100644 --- a/products/ASC.Files/Core/Core/Thirdparty/IThirdPartyProviderDao.cs +++ b/products/ASC.Files/Core/Core/Thirdparty/IThirdPartyProviderDao.cs @@ -77,6 +77,16 @@ internal abstract class ThirdPartyProviderDao return Task.CompletedTask; } + public virtual Task GetThumbnailAsync(File file, int width, int height) + { + return GetThumbnailAsync(file.Id, width, height); + } + + public virtual Task GetThumbnailAsync(string file, int width, int height) + { + return Task.FromResult(null); + } + public Task GetProperties(string fileId) { return Task.FromResult(null); diff --git a/products/ASC.Files/Core/Core/Thirdparty/OneDrive/OneDriveFileDao.cs b/products/ASC.Files/Core/Core/Thirdparty/OneDrive/OneDriveFileDao.cs index 61382da824..5dd4e1eefa 100644 --- a/products/ASC.Files/Core/Core/Thirdparty/OneDrive/OneDriveFileDao.cs +++ b/products/ASC.Files/Core/Core/Thirdparty/OneDrive/OneDriveFileDao.cs @@ -561,12 +561,7 @@ internal class OneDriveFileDao : OneDriveDaoBase, IFileDao return false; } - public Task GetThumbnailAsync(File file, int width, int height) - { - return GetThumbnailAsync(file.Id, width, height); - } - - public Task GetThumbnailAsync(string fileId, int width, int height) + public override Task GetThumbnailAsync(string fileId, int width, int height) { var oneDriveId = MakeOneDriveId(_oneDriveDaoSelector.ConvertId(fileId)); return ProviderInfo.GetThumbnailAsync(oneDriveId, width, height); diff --git a/products/ASC.Files/Core/Core/Thirdparty/ProviderDao/ProviderFileDao.cs b/products/ASC.Files/Core/Core/Thirdparty/ProviderDao/ProviderFileDao.cs index e11365c946..9b4c569010 100644 --- a/products/ASC.Files/Core/Core/Thirdparty/ProviderDao/ProviderFileDao.cs +++ b/products/ASC.Files/Core/Core/Thirdparty/ProviderDao/ProviderFileDao.cs @@ -464,7 +464,7 @@ internal class ProviderFileDao : ProviderDaoBase, IFileDao var selector = GetSelector(file.Id); var fileDao = selector.GetFileDao(file.Id); - return fileDao.UseTrashForRemove(file); + return fileDao.UseTrashForRemove(file); } #region chunking @@ -521,14 +521,14 @@ internal class ProviderFileDao : ProviderDaoBase, IFileDao return file; } - public Task GetThumbnailAsync(string fileId, int width, int height) + public override Task GetThumbnailAsync(string fileId, int width, int height) { var selector = GetSelector(fileId); var fileDao = selector.GetFileDao(fileId); return fileDao.GetThumbnailAsync(fileId, width, height); } - public Task GetThumbnailAsync(File file, int width, int height) + public override Task GetThumbnailAsync(File file, int width, int height) { var fileDao = GetFileDao(file); return fileDao.GetThumbnailAsync(file, width, height); diff --git a/products/ASC.Files/Core/Core/Thirdparty/SharePoint/SharePointFileDao.cs b/products/ASC.Files/Core/Core/Thirdparty/SharePoint/SharePointFileDao.cs index 23dfffca37..cefa18c15c 100644 --- a/products/ASC.Files/Core/Core/Thirdparty/SharePoint/SharePointFileDao.cs +++ b/products/ASC.Files/Core/Core/Thirdparty/SharePoint/SharePointFileDao.cs @@ -475,14 +475,4 @@ internal class SharePointFileDao : SharePointDaoBase, IFileDao return file; } - - public Task GetThumbnailAsync(string fileid, int width, int height) - { - return null; - } - - public Task GetThumbnailAsync(File file, int width, int height) - { - return null; - } } diff --git a/products/ASC.Files/Core/Core/Thirdparty/Sharpbox/SharpBoxFileDao.cs b/products/ASC.Files/Core/Core/Thirdparty/Sharpbox/SharpBoxFileDao.cs index a64eea7ed4..18da41fc94 100644 --- a/products/ASC.Files/Core/Core/Thirdparty/Sharpbox/SharpBoxFileDao.cs +++ b/products/ASC.Files/Core/Core/Thirdparty/Sharpbox/SharpBoxFileDao.cs @@ -569,16 +569,6 @@ internal class SharpBoxFileDao : SharpBoxDaoBase, IFileDao return false; } - public Task GetThumbnailAsync(string fileid, int width, int height) - { - return null; - } - - public Task GetThumbnailAsync(File file, int width, int height) - { - return null; - } - #region chunking public async Task> CreateUploadSessionAsync(File file, long contentLength) diff --git a/products/ASC.Files/Core/Services/FFmpegService/FFmpeg.cs b/products/ASC.Files/Core/Services/FFmpegService/FFmpeg.cs index f759a1156e..8365765838 100644 --- a/products/ASC.Files/Core/Services/FFmpegService/FFmpeg.cs +++ b/products/ASC.Files/Core/Services/FFmpegService/FFmpeg.cs @@ -81,7 +81,7 @@ public class FFmpegService { process.Start(); - await StreamCopyToAsync(inputStream, process.StandardInput.BaseStream, closeDst: true); + await inputStream.CopyToAsync(process.StandardInput.BaseStream); await ProcessLog(process.StandardError.BaseStream); @@ -94,7 +94,7 @@ public class FFmpegService _logger = logger; _fFmpegPath = configuration["files:ffmpeg:value"]; _fFmpegArgs = configuration["files:ffmpeg:args"] ?? "-i - -preset ultrafast -movflags frag_keyframe+empty_moov -f {0} -"; - _fFmpegThumbnailsArgs = configuration["files:ffmpeg:thumbnails:args"] ?? "-i - -vf \"thumbnail\" {0}"; + _fFmpegThumbnailsArgs = configuration["files:ffmpeg:thumbnails:args"] ?? "-ss 3 -i \"{0}\" -vf \"thumbnail\" -frames:v 1 -vsync vfr \"{1}\" -y"; _convertableMedia = (configuration.GetSection("files:ffmpeg:exts").Get() ?? Array.Empty()).ToList(); @@ -163,44 +163,6 @@ public class FFmpegService return startInfo; } - private Task StreamCopyToAsync(Stream srcStream, Stream dstStream, bool closeSrc = false, bool closeDst = false) - { - ArgumentNullException.ThrowIfNull(srcStream); - ArgumentNullException.ThrowIfNull(dstStream); - - return StreamCopyToAsyncInternal(srcStream, dstStream, closeSrc, closeDst); - } - - private async Task StreamCopyToAsyncInternal(Stream srcStream, Stream dstStream, bool closeSrc, bool closeDst) - { - const int bufs = 2048 * 4; - - var buffer = new byte[bufs]; - int readed; - var total = 0; - while ((readed = await srcStream.ReadAsync(buffer, 0, bufs)) > 0) - { - await dstStream.WriteAsync(buffer, 0, readed); - await dstStream.FlushAsync(); - total += readed; - } - - if (closeSrc) - { - srcStream.Dispose(); - srcStream.Close(); - } - - if (closeDst) - { - await dstStream.FlushAsync(); - dstStream.Dispose(); - dstStream.Close(); - } - - return total; - } - private async Task ProcessLog(Stream stream) { using var reader = new StreamReader(stream, Encoding.UTF8); @@ -211,81 +173,17 @@ public class FFmpegService } } - public async Task CreateThumbnail(Stream stream, string tempPath) + public async Task CreateThumbnail(string sourcePath, string destPath) { - var startInfo = PrepareFFmpegForCreateThumbnail(tempPath); + var startInfo = PrepareCommonFFmpeg(); + startInfo.Arguments = string.Format(_fFmpegThumbnailsArgs, sourcePath, destPath); Process process; using (process = new Process { StartInfo = startInfo }) { process.Start(); - - await StreamCopyForThumbnailAsync(stream, process.StandardInput.BaseStream, closeDst: true); - + process.WaitForExit(10000); await ProcessLog(process.StandardError.BaseStream); - - return GetFileStream(tempPath); - } - } - - private ProcessStartInfo PrepareFFmpegForCreateThumbnail(string tempFile) - { - var startInfo = PrepareCommonFFmpeg(); - - startInfo.Arguments = string.Format(_fFmpegThumbnailsArgs, tempFile); - - return startInfo; - } - - private Task StreamCopyForThumbnailAsync(Stream srcStream, Stream dstStream, bool closeSrc = false, bool closeDst = false) - { - ArgumentNullException.ThrowIfNull(srcStream); - ArgumentNullException.ThrowIfNull(dstStream); - - return StreamCopyForThumbnailAsyncInternal(srcStream, dstStream, closeSrc, closeDst); - } - - private async Task StreamCopyForThumbnailAsyncInternal(Stream srcStream, Stream dstStream, bool closeSrc, bool closeDst) - { - const int bufs = 2048 * 4; - - var buffer = new byte[bufs]; - int readed; - var total = 0; - - while ((readed = await srcStream.ReadAsync(buffer, 0, bufs)) > 0 && total < 9000000) // HACK: ffmpeg lock stream when total < 9000000 - { - await dstStream.WriteAsync(buffer, 0, readed); - await dstStream.FlushAsync(); - total += readed; - } - - if (closeSrc) - { - srcStream.Dispose(); - srcStream.Close(); - } - - if (closeDst) - { - await dstStream.FlushAsync(); - dstStream.Dispose(); - dstStream.Close(); - } - - return total; - } - - private Stream GetFileStream(string tempFile) - { - if (File.Exists(tempFile)) - { - return File.Open(tempFile, FileMode.Open); - } - else - { - _logger.ErrorFileNotFound(tempFile); - throw new IOException("file not found"); } } } diff --git a/products/ASC.Files/Service/Thumbnail/Builder.cs b/products/ASC.Files/Service/Thumbnail/Builder.cs index 8316d46466..376d9b9b6e 100644 --- a/products/ASC.Files/Service/Thumbnail/Builder.cs +++ b/products/ASC.Files/Service/Thumbnail/Builder.cs @@ -80,6 +80,7 @@ public class Builder private readonly PathProvider _pathProvider; private readonly IHttpClientFactory _clientFactory; private readonly ThumbnailSettings _thumbnailSettings; + private readonly TempStream _tempStream; private readonly SocketManager _socketManager; private readonly FFmpegService _fFmpegService; private readonly TempPath _tempPath; @@ -97,7 +98,8 @@ public class Builder FFmpegService fFmpegService, TempPath tempPath, SocketManager socketManager, - ThumbnailSettings thumbnailSettings) + ThumbnailSettings thumbnailSettings, + TempStream tempStream) { _config = settings; _tenantManager = tenantManager; @@ -112,6 +114,7 @@ public class Builder _tempPath = tempPath; _socketManager = socketManager; _thumbnailSettings = thumbnailSettings; + _tempStream = tempStream; } internal async Task BuildThumbnail(FileData fileData) @@ -178,16 +181,18 @@ public class Builder if (IsVideo(file)) { await MakeThumbnailFromVideo(fileDao, file); - return; - } - - if (IsImage(file)) - { - await CropImage(fileDao, file); } else { - await MakeThumbnail(fileDao, file); + + if (IsImage(file)) + { + await CropImage(fileDao, file); + } + else + { + await MakeThumbnail(fileDao, file); + } } var newFile = await fileDao.GetFileStableAsync(file.Id); @@ -212,20 +217,23 @@ public class Builder { var streamFile = await fileDao.GetFileStreamAsync(file); - var tempPath = GetTempPath(); - var streamThumb = await _fFmpegService.CreateThumbnail(streamFile, tempPath); + var thumbPath = _tempPath.GetTempFileName("jpg"); + var tempFilePath = _tempPath.GetTempFileName(Path.GetExtension(file.Title)); - await Crop(fileDao, file, streamThumb); + using (var fileStream = new FileStream(tempFilePath, FileMode.Open, FileAccess.ReadWrite, System.IO.FileShare.Read)) + { + await streamFile.CopyToAsync(fileStream); + } - streamThumb.Dispose(); - streamThumb.Close(); + await _fFmpegService.CreateThumbnail(tempFilePath, thumbPath); - File.Delete(tempPath); - } + using (var streamThumb = new FileStream(thumbPath, FileMode.Open, FileAccess.ReadWrite, System.IO.FileShare.Read)) + { + await Crop(fileDao, file, streamThumb); + } - private string GetTempPath() - { - return Path.Combine(_tempPath.GetTempPath(), Path.ChangeExtension(Path.GetRandomFileName(), "jpg")); + File.Delete(thumbPath); + File.Delete(tempFilePath); } private async Task MakeThumbnail(IFileDao fileDao, File file) @@ -398,8 +406,7 @@ public class Builder private async ValueTask CropAsync(Image sourceImg, IFileDao fileDao, File file, int width, int height) { - var targetSize = new Size(Math.Min(sourceImg.Width, width), Math.Min(sourceImg.Height, height)); - using var targetImg = GetImageThumbnail(sourceImg, targetSize, width, height); + using var targetImg = GetImageThumbnail(sourceImg, width); using var targetStream = new MemoryStream(); switch (_global.ThumbnailExtension) { @@ -431,7 +438,7 @@ public class Builder await fileDao.SaveThumbnailAsync(file, targetStream, width, height); } - private Image GetImageThumbnail(Image sourceBitmap, Size targetSize, int thumbnaillWidth, int thumbnaillHeight) + private Image GetImageThumbnail(Image sourceBitmap, int thumbnaillWidth) { return sourceBitmap.Clone(x => x.BackgroundColor(Color.White).Resize(thumbnaillWidth, 0)); } From 4ad4c34b34486f6a1e8b0bcccffd1e23cfec81e5 Mon Sep 17 00:00:00 2001 From: pavelbannov Date: Fri, 24 Jun 2022 16:23:56 +0300 Subject: [PATCH 15/23] fix --- common/ASC.Common/GlobalUsings.cs | 1 + 1 file changed, 1 insertion(+) diff --git a/common/ASC.Common/GlobalUsings.cs b/common/ASC.Common/GlobalUsings.cs index d033a5cfef..d701a590e6 100644 --- a/common/ASC.Common/GlobalUsings.cs +++ b/common/ASC.Common/GlobalUsings.cs @@ -86,6 +86,7 @@ global using Microsoft.Extensions.Caching.Memory; global using Microsoft.Extensions.Configuration; global using Microsoft.Extensions.DependencyInjection; global using Microsoft.Extensions.DependencyInjection.Extensions; +global using Microsoft.Extensions.Hosting; global using Microsoft.Extensions.Logging; global using Microsoft.Extensions.Options; global using Microsoft.Extensions.Primitives; From de51c8e1db36826c937ee5d96d27901ad56da30f Mon Sep 17 00:00:00 2001 From: SuhorukovAnton Date: Mon, 27 Jun 2022 16:40:26 +0300 Subject: [PATCH 16/23] box: fix GetThumbnail --- .../Core/Core/Thirdparty/Box/BoxStorage.cs | 19 ++++--------------- 1 file changed, 4 insertions(+), 15 deletions(-) diff --git a/products/ASC.Files/Core/Core/Thirdparty/Box/BoxStorage.cs b/products/ASC.Files/Core/Core/Thirdparty/Box/BoxStorage.cs index d37e581d73..b0b41a8d76 100644 --- a/products/ASC.Files/Core/Core/Thirdparty/Box/BoxStorage.cs +++ b/products/ASC.Files/Core/Core/Thirdparty/Box/BoxStorage.cs @@ -273,21 +273,10 @@ internal class BoxStorage public async Task GetThumbnailAsync(string fileId, int width, int height) { - if (await CanGetThumbnailAsync(fileId)) - { - return await _boxClient.FilesManager.GetThumbnailAsync(fileId, width, height, extension: "jpg"); - } - else - { - return null; - } - } - - private async Task CanGetThumbnailAsync(string fileId) - { - var file = await GetFileAsync(fileId); - var extension = FileUtility.GetFileExtension(file.Name); - return FileUtility.ExtsVideo.Contains(extension) || FileUtility.ExtsImage.Contains(extension); + var boxRepresentation = new BoxRepresentationRequest(); + boxRepresentation.FileId = fileId; + boxRepresentation.XRepHints = $"[jpg?dimensions=320x320]"; + return await _boxClient.FilesManager.GetRepresentationContentAsync(boxRepresentation); } } From 5cc38b95dff9595f1b444a7dbe15f6286cec2807 Mon Sep 17 00:00:00 2001 From: SuhorukovAnton Date: Tue, 28 Jun 2022 14:39:20 +0300 Subject: [PATCH 17/23] add fFmpegFormats and imageFormatsCanBeCrop --- .../ASC.Files/Core/Core/ThumbnailSettings.cs | 2 +- .../Core/Services/FFmpegService/FFmpeg.cs | 14 +++++++++++ .../ASC.Files/Service/Thumbnail/Builder.cs | 25 +++++++++++-------- 3 files changed, 30 insertions(+), 11 deletions(-) diff --git a/products/ASC.Files/Core/Core/ThumbnailSettings.cs b/products/ASC.Files/Core/Core/ThumbnailSettings.cs index 2a0fcb68d5..9344914096 100644 --- a/products/ASC.Files/Core/Core/ThumbnailSettings.cs +++ b/products/ASC.Files/Core/Core/ThumbnailSettings.cs @@ -65,7 +65,7 @@ public class ThumbnailSettings private string _formats; public string Formats { - get => _formats ?? ".pptx|.pptm|.ppt|.ppsx|.ppsm|.pps|.potx|.potm|.pot|.odp|.fodp|.otp|.gslides|.xlsx|.xlsm|.xls|.xltx|.xltm|.xlt|.ods|.fods|.ots|.gsheet|.csv|.docx|.docxf|.oform|.docm|.doc|.dotx|.dotm|.dot|.odt|.fodt|.ott|.gdoc|.txt|.rtf|.mht|.html|.htm|.fb2|.epub|.pdf|.djvu|.xps|.oxps|.bmp|.jpeg|.jpg|.png|.gif|.tiff|.tif|.ico|.mp4"; + get => _formats ?? ".pptx|.pptm|.ppt|.ppsx|.ppsm|.pps|.potx|.potm|.pot|.odp|.fodp|.otp|.gslides|.xlsx|.xlsm|.xls|.xltx|.xltm|.xlt|.ods|.fods|.ots|.gsheet|.csv|.docx|.docxf|.oform|.docm|.doc|.dotx|.dotm|.dot|.odt|.fodt|.ott|.gdoc|.txt|.rtf|.mht|.html|.htm|.fb2|.epub|.pdf|.djvu|.xps|.oxps"; set => _formats = value; } diff --git a/products/ASC.Files/Core/Services/FFmpegService/FFmpeg.cs b/products/ASC.Files/Core/Services/FFmpegService/FFmpeg.cs index 8365765838..0b4bece49f 100644 --- a/products/ASC.Files/Core/Services/FFmpegService/FFmpeg.cs +++ b/products/ASC.Files/Core/Services/FFmpegService/FFmpeg.cs @@ -49,6 +49,7 @@ public class FFmpegService private readonly string _fFmpegPath; private readonly string _fFmpegArgs; private readonly string _fFmpegThumbnailsArgs; + private readonly List _fFmpegFormats; private readonly ILogger _logger; @@ -57,6 +58,11 @@ public class FFmpegService return MustConvertable.Contains(extension.TrimStart('.')); } + public bool ExistFormat(string extension) + { + return _fFmpegFormats.Contains(extension); + } + public Task Convert(Stream inputStream, string inputFormat) { if (inputStream == null) @@ -95,6 +101,14 @@ public class FFmpegService _fFmpegPath = configuration["files:ffmpeg:value"]; _fFmpegArgs = configuration["files:ffmpeg:args"] ?? "-i - -preset ultrafast -movflags frag_keyframe+empty_moov -f {0} -"; _fFmpegThumbnailsArgs = configuration["files:ffmpeg:thumbnails:args"] ?? "-ss 3 -i \"{0}\" -vf \"thumbnail\" -frames:v 1 -vsync vfr \"{1}\" -y"; + _fFmpegFormats = configuration.GetSection("files:ffmpeg:thumbnails:formats").Get>() ?? new List + { + ".3gp", ".asf", ".avi", ".f4v", + ".fla", ".flv", ".m2ts", ".m4v", + ".mkv", ".mov", ".mp4", ".mpeg", + ".mpg", ".mts", ".ogv", ".svi", + ".vob", ".webm", ".wmv" + }; _convertableMedia = (configuration.GetSection("files:ffmpeg:exts").Get() ?? Array.Empty()).ToList(); diff --git a/products/ASC.Files/Service/Thumbnail/Builder.cs b/products/ASC.Files/Service/Thumbnail/Builder.cs index 376d9b9b6e..cf6d9cc5d5 100644 --- a/products/ASC.Files/Service/Thumbnail/Builder.cs +++ b/products/ASC.Files/Service/Thumbnail/Builder.cs @@ -85,6 +85,10 @@ public class Builder private readonly FFmpegService _fFmpegService; private readonly TempPath _tempPath; + private readonly List _imageFormatsCanBeCrop = new List + { + ".bmp", ".gif", ".jpeg", ".jpg", ".pbm", ".png", ".tiff", ".tga", ".webp", + }; public Builder( ThumbnailSettings settings, TenantManager tenantManager, @@ -167,7 +171,7 @@ public class Builder var ext = FileUtility.GetFileExtension(file.Title); - if (!_config.FormatsArray.Contains(ext) || file.Encrypted || file.RootFolderType == FolderType.TRASH || file.ContentLength > _config.AvailableFileSize) + if (!CanCreateThumbnail(ext) || file.Encrypted || file.RootFolderType == FolderType.TRASH || file.ContentLength > _config.AvailableFileSize) { file.ThumbnailStatus = ASC.Files.Core.Thumbnail.NotRequired; foreach (var size in _thumbnailSettings.Sizes) @@ -178,14 +182,14 @@ public class Builder return; } - if (IsVideo(file)) + if (IsVideo(ext)) { await MakeThumbnailFromVideo(fileDao, file); } else { - if (IsImage(file)) + if (IsImage(ext)) { await CropImage(fileDao, file); } @@ -354,18 +358,19 @@ public class Builder _logger.DebugMakeThumbnail4(file.Id.ToString()); } - private bool IsImage(File file) + private bool CanCreateThumbnail(string extention) { - var extension = FileUtility.GetFileExtension(file.Title); - - return FileUtility.ExtsImage.Contains(extension); + return _config.FormatsArray.Contains(extention) || IsVideo(extention) || IsImage(extention); } - private bool IsVideo(File file) + private bool IsImage(string extention) { - var extension = FileUtility.GetFileExtension(file.Title); + return _imageFormatsCanBeCrop.Contains(extention); + } - return FileUtility.ExtsVideo.Contains(extension); + private bool IsVideo(string extention) + { + return _fFmpegService.ExistFormat(extention); } private async Task CropImage(IFileDao fileDao, File file) From 83bb63ff0c80b49cab801057e98c78e60926fa34 Mon Sep 17 00:00:00 2001 From: SuhorukovAnton Date: Tue, 28 Jun 2022 15:33:22 +0300 Subject: [PATCH 18/23] remove waste --- common/ASC.FederatedLogin/LoginProviders/GoogleLoginProvider.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/common/ASC.FederatedLogin/LoginProviders/GoogleLoginProvider.cs b/common/ASC.FederatedLogin/LoginProviders/GoogleLoginProvider.cs index 7bd5b40169..082d8e35bd 100644 --- a/common/ASC.FederatedLogin/LoginProviders/GoogleLoginProvider.cs +++ b/common/ASC.FederatedLogin/LoginProviders/GoogleLoginProvider.cs @@ -47,7 +47,7 @@ public class GoogleLoginProvider : BaseLoginProvider public static readonly string[] GoogleDriveExt = new[] { ".gdoc", ".gsheet", ".gslides", ".gdraw" }; public static readonly string GoogleDriveMimeTypeFolder = "application/vnd.google-apps.folder"; - public static readonly string FilesFields = "id,name,mimeType,parents,createdTime,modifiedTime,owners/displayName,lastModifyingUser/displayName,capabilities/canEdit,size,thumbnailLink"; + public static readonly string FilesFields = "id,name,mimeType,parents,createdTime,modifiedTime,owners/displayName,lastModifyingUser/displayName,capabilities/canEdit,size"; public static readonly string ProfileFields = "emailAddresses,genders,names"; private readonly RequestHelper _requestHelper; From fa815c62549c17c3f671a1565c54874e4e0eaae5 Mon Sep 17 00:00:00 2001 From: SuhorukovAnton Date: Tue, 28 Jun 2022 14:50:46 +0300 Subject: [PATCH 19/23] fix order endpoints --- common/ASC.Api.Core/Core/CustomEndpointDataSource.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/common/ASC.Api.Core/Core/CustomEndpointDataSource.cs b/common/ASC.Api.Core/Core/CustomEndpointDataSource.cs index 76b2ef8884..d160d45a15 100644 --- a/common/ASC.Api.Core/Core/CustomEndpointDataSource.cs +++ b/common/ASC.Api.Core/Core/CustomEndpointDataSource.cs @@ -60,7 +60,7 @@ public class CustomEndpointDataSource : EndpointDataSource void AddEndpoints(IReadOnlyDictionary defaults = null, RouteValueDictionary policies = null) { - var order = constraintRouteAttr != null ? r.Order : r.Order + 2; + var order = constraintRouteAttr != null ? r.Order - 1 : r.Order; endpoints.Add(new RouteEndpoint(r.RequestDelegate, RoutePatternFactory.Parse(r.RoutePattern.RawText, defaults, policies), order, r.Metadata, r.DisplayName)); endpoints.Add(new RouteEndpoint(r.RequestDelegate, RoutePatternFactory.Parse(r.RoutePattern.RawText + ".{format}", defaults, policies), order - 1, r.Metadata, r.DisplayName)); } From 21ea7ec01987e4e2d5038f321aa190c80b5d4a01 Mon Sep 17 00:00:00 2001 From: SuhorukovAnton Date: Wed, 29 Jun 2022 11:55:54 +0300 Subject: [PATCH 20/23] first version: delete expired service --- .../Service/Expired/DeleteExpiredService.cs | 50 +++++++++++++++++++ products/ASC.Files/Service/GlobalUsings.cs | 8 ++- products/ASC.Files/Service/Program.cs | 3 ++ 3 files changed, 56 insertions(+), 5 deletions(-) create mode 100644 products/ASC.Files/Service/Expired/DeleteExpiredService.cs diff --git a/products/ASC.Files/Service/Expired/DeleteExpiredService.cs b/products/ASC.Files/Service/Expired/DeleteExpiredService.cs new file mode 100644 index 0000000000..b8cb82a16a --- /dev/null +++ b/products/ASC.Files/Service/Expired/DeleteExpiredService.cs @@ -0,0 +1,50 @@ +// (c) Copyright Ascensio System SIA 2010-2022 +// +// This program is a free software product. +// You can redistribute it and/or modify it under the terms +// of the GNU Affero General Public License (AGPL) version 3 as published by the Free Software +// Foundation. In accordance with Section 7(a) of the GNU AGPL its Section 15 shall be amended +// to the effect that Ascensio System SIA expressly excludes the warranty of non-infringement of +// any third-party rights. +// +// This program is distributed WITHOUT ANY WARRANTY, without even the implied warranty +// of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. For details, see +// the GNU AGPL at: http://www.gnu.org/licenses/agpl-3.0.html +// +// You can contact Ascensio System SIA at Lubanas st. 125a-25, Riga, Latvia, EU, LV-1021. +// +// The interactive user interfaces in modified source and object code versions of the Program must +// display Appropriate Legal Notices, as required under Section 5 of the GNU AGPL version 3. +// +// Pursuant to Section 7(b) of the License you must retain the original Product logo when +// distributing the program. Pursuant to Section 7(e) we decline to grant you any rights under +// trademark law for use of our trademarks. +// +// All the Product's GUI elements, including illustrations and icon sets, as well as technical writing +// content are licensed under the terms of the Creative Commons Attribution-ShareAlike 4.0 +// International. See the License terms at http://creativecommons.org/licenses/by-sa/4.0/legalcode + +namespace ASC.Files.Expired; + +[Singletone] +public class DeleteExpiredService : BackgroundService +{ + private readonly CommonChunkedUploadSessionHolder _commonChunkedUploadSessionHolder; + public DeleteExpiredService( + ILogger log, + SetupInfo setupInfo, + TempPath tempPath, + GlobalStore globalStore) + { + _commonChunkedUploadSessionHolder = new CommonChunkedUploadSessionHolder(tempPath, log, globalStore.GetStore(false), FileConstant.StorageDomainTmp, setupInfo.ChunkUploadSize); + } + + protected override async Task ExecuteAsync(CancellationToken stoppingToken) + { + while (!stoppingToken.IsCancellationRequested) + { + await _commonChunkedUploadSessionHolder.DeleteExpiredAsync(); + await Task.Delay(TimeSpan.FromDays(1), stoppingToken); + } + } +} \ No newline at end of file diff --git a/products/ASC.Files/Service/GlobalUsings.cs b/products/ASC.Files/Service/GlobalUsings.cs index dfb57e8a05..e445d3cd84 100644 --- a/products/ASC.Files/Service/GlobalUsings.cs +++ b/products/ASC.Files/Service/GlobalUsings.cs @@ -31,14 +31,14 @@ global using System.Reflection; global using System.Text.Json; global using ASC.Api.Core; -global using ASC.Api.Core.Extensions; +global using ASC.Api.Core.Extensions; global using ASC.Common; global using ASC.Common.Caching; global using ASC.Common.DependencyInjection; global using ASC.Common.Log; global using ASC.Common.Mapping; -global using ASC.Common.Utils; global using ASC.Core; +global using ASC.Core.ChunkedUploader; global using ASC.Core.Common; global using ASC.Core.Common.EF; global using ASC.Core.Common.Hosting; @@ -60,14 +60,13 @@ global using ASC.Files.Core.IntegrationEvents.Events; global using ASC.Files.Core.Log; global using ASC.Files.Core.Resources; global using ASC.Files.Core.Security; +global using ASC.Files.Expired; global using ASC.Files.Service.Log; global using ASC.Files.ThumbnailBuilder; global using ASC.Thumbnail.IntegrationEvents.EventHandling; global using ASC.Web.Core; global using ASC.Web.Core.Files; -global using ASC.Web.Core.Users; global using ASC.Web.Files.Classes; -global using ASC.Web.Files.Core; global using ASC.Web.Files.Core.Search; global using ASC.Web.Files.Services.DocumentService; global using ASC.Web.Files.Utils; @@ -80,6 +79,5 @@ global using Microsoft.Extensions.Hosting.WindowsServices; global using Microsoft.Extensions.Logging; global using SixLabors.ImageSharp; -global using SixLabors.ImageSharp.Formats.Png; global using static ASC.Web.Core.Files.DocumentService; \ No newline at end of file diff --git a/products/ASC.Files/Service/Program.cs b/products/ASC.Files/Service/Program.cs index 27f5473b6a..8288bb19c4 100644 --- a/products/ASC.Files/Service/Program.cs +++ b/products/ASC.Files/Service/Program.cs @@ -82,6 +82,9 @@ builder.Host.ConfigureDefault(args, (hostContext, config, env, path) => services.AddHostedService(); diHelper.TryAdd(); + services.AddHostedService(); + diHelper.TryAdd(); + diHelper.TryAdd(); diHelper.TryAdd(); diHelper.TryAdd(); From 5ccd9d01a5a85ed7b83f51bfc5b12e21ae4431ab Mon Sep 17 00:00:00 2001 From: pavelbannov Date: Wed, 29 Jun 2022 18:34:50 +0300 Subject: [PATCH 21/23] DeleteExpiredService: launch frequency --- .../Service/Expired/DeleteExpiredService.cs | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/products/ASC.Files/Service/Expired/DeleteExpiredService.cs b/products/ASC.Files/Service/Expired/DeleteExpiredService.cs index b8cb82a16a..6b6371a6fa 100644 --- a/products/ASC.Files/Service/Expired/DeleteExpiredService.cs +++ b/products/ASC.Files/Service/Expired/DeleteExpiredService.cs @@ -29,13 +29,17 @@ namespace ASC.Files.Expired; [Singletone] public class DeleteExpiredService : BackgroundService { - private readonly CommonChunkedUploadSessionHolder _commonChunkedUploadSessionHolder; + private readonly CommonChunkedUploadSessionHolder _commonChunkedUploadSessionHolder; + private readonly TimeSpan _launchFrequency; + public DeleteExpiredService( ILogger log, SetupInfo setupInfo, TempPath tempPath, - GlobalStore globalStore) - { + GlobalStore globalStore, + IConfiguration configuration) + { + _launchFrequency = TimeSpan.Parse(configuration["files:deleteExpired"] ?? "1", CultureInfo.InvariantCulture); _commonChunkedUploadSessionHolder = new CommonChunkedUploadSessionHolder(tempPath, log, globalStore.GetStore(false), FileConstant.StorageDomainTmp, setupInfo.ChunkUploadSize); } @@ -44,7 +48,7 @@ public class DeleteExpiredService : BackgroundService while (!stoppingToken.IsCancellationRequested) { await _commonChunkedUploadSessionHolder.DeleteExpiredAsync(); - await Task.Delay(TimeSpan.FromDays(1), stoppingToken); + await Task.Delay(_launchFrequency, stoppingToken); } } } \ No newline at end of file From 35ab5a3531a0bb290671e8610c45dbadeecbab39 Mon Sep 17 00:00:00 2001 From: pavelbannov Date: Wed, 29 Jun 2022 19:43:29 +0300 Subject: [PATCH 22/23] fix order --- common/ASC.Api.Core/Core/CustomEndpointDataSource.cs | 6 +++--- products/ASC.Files/Server/Api/FilesController.cs | 2 +- products/ASC.Files/Server/Api/UploadController.cs | 4 ++-- web/ASC.Web.Api/Api/AuthenticationController.cs | 2 +- 4 files changed, 7 insertions(+), 7 deletions(-) diff --git a/common/ASC.Api.Core/Core/CustomEndpointDataSource.cs b/common/ASC.Api.Core/Core/CustomEndpointDataSource.cs index d160d45a15..71ff6246af 100644 --- a/common/ASC.Api.Core/Core/CustomEndpointDataSource.cs +++ b/common/ASC.Api.Core/Core/CustomEndpointDataSource.cs @@ -60,9 +60,9 @@ public class CustomEndpointDataSource : EndpointDataSource void AddEndpoints(IReadOnlyDictionary defaults = null, RouteValueDictionary policies = null) { - var order = constraintRouteAttr != null ? r.Order - 1 : r.Order; - endpoints.Add(new RouteEndpoint(r.RequestDelegate, RoutePatternFactory.Parse(r.RoutePattern.RawText, defaults, policies), order, r.Metadata, r.DisplayName)); - endpoints.Add(new RouteEndpoint(r.RequestDelegate, RoutePatternFactory.Parse(r.RoutePattern.RawText + ".{format}", defaults, policies), order - 1, r.Metadata, r.DisplayName)); + var order = constraintRouteAttr != null ? r.Order : r.Order + 2; + endpoints.Add(new RouteEndpoint(r.RequestDelegate, RoutePatternFactory.Parse(r.RoutePattern.RawText, defaults, policies), order + 1, r.Metadata, r.DisplayName)); + endpoints.Add(new RouteEndpoint(r.RequestDelegate, RoutePatternFactory.Parse(r.RoutePattern.RawText + ".{format}", defaults, policies), order, r.Metadata, r.DisplayName)); } }).ToList(); diff --git a/products/ASC.Files/Server/Api/FilesController.cs b/products/ASC.Files/Server/Api/FilesController.cs index ec199a9e2d..13299a0067 100644 --- a/products/ASC.Files/Server/Api/FilesController.cs +++ b/products/ASC.Files/Server/Api/FilesController.cs @@ -61,7 +61,7 @@ public class FilesControllerThirdparty : FilesController _documentServiceHelper = documentServiceHelper; } - [HttpGet("file/app-{fileId}", Order = int.MaxValue)] + [HttpGet("file/app-{fileId}", Order = 1)] public async Task GetFileInfoThirdPartyAsync(string fileId) { fileId = "app-" + fileId; diff --git a/products/ASC.Files/Server/Api/UploadController.cs b/products/ASC.Files/Server/Api/UploadController.cs index 8d88887b43..78e10041a5 100644 --- a/products/ASC.Files/Server/Api/UploadController.cs +++ b/products/ASC.Files/Server/Api/UploadController.cs @@ -104,7 +104,7 @@ public abstract class UploadController : ApiControllerBase /// Keep status conversation after finishing /// Uploads /// - [HttpPost("{folderId}/insert", Order = int.MaxValue)] + [HttpPost("{folderId}/insert", Order = 1)] public Task> InsertFileAsync(T folderId, [FromForm][ModelBinder(BinderType = typeof(InsertFileModelBinder))] InsertFileRequestDto inDto) { return _filesControllerHelper.InsertFileAsync(folderId, inDto.Stream, inDto.Title, inDto.CreateNewIfExist, inDto.KeepConvertStatus); @@ -133,7 +133,7 @@ public abstract class UploadController : ApiControllerBase /// If True, upload documents in original formats as well /// Keep status conversation after finishing /// Uploaded file - [HttpPost("{folderId}/upload", Order = int.MaxValue)] + [HttpPost("{folderId}/upload", Order = 1)] public Task UploadFileAsync(T folderId, [ModelBinder(BinderType = typeof(UploadModelBinder))] UploadRequestDto inDto) { return _filesControllerHelper.UploadFileAsync(folderId, inDto); diff --git a/web/ASC.Web.Api/Api/AuthenticationController.cs b/web/ASC.Web.Api/Api/AuthenticationController.cs index c77564d436..e9de9d48ea 100644 --- a/web/ASC.Web.Api/Api/AuthenticationController.cs +++ b/web/ASC.Web.Api/Api/AuthenticationController.cs @@ -144,7 +144,7 @@ public class AuthenticationController : ControllerBase } [AllowNotPayment] - [HttpPost("{code}", Order = int.MaxValue)] + [HttpPost("{code}", Order = 1)] public AuthenticationTokenDto AuthenticateMeFromBodyWithCode(AuthRequestsDto inDto) { var tenant = _tenantManager.GetCurrentTenant().Id; From de068f869e6a02b7a64d78983b8072fc91411c6f Mon Sep 17 00:00:00 2001 From: pavelbannov Date: Wed, 29 Jun 2022 20:55:01 +0300 Subject: [PATCH 23/23] thumb: fix --- .../Core/Services/FFmpegService/FFmpeg.cs | 32 ++++++------------- .../ASC.Files/Service/Thumbnail/Builder.cs | 6 ++-- 2 files changed, 11 insertions(+), 27 deletions(-) diff --git a/products/ASC.Files/Core/Services/FFmpegService/FFmpeg.cs b/products/ASC.Files/Core/Services/FFmpegService/FFmpeg.cs index 0b4bece49f..b28fa7317b 100644 --- a/products/ASC.Files/Core/Services/FFmpegService/FFmpeg.cs +++ b/products/ASC.Files/Core/Services/FFmpegService/FFmpeg.cs @@ -82,17 +82,13 @@ public class FFmpegService { var startInfo = PrepareFFmpeg(inputFormat); - Process process; - using (process = new Process { StartInfo = startInfo }) - { - process.Start(); + using var process = Process.Start(startInfo); - await inputStream.CopyToAsync(process.StandardInput.BaseStream); + await inputStream.CopyToAsync(process.StandardInput.BaseStream); - await ProcessLog(process.StandardError.BaseStream); + await ProcessLog(process.StandardError.BaseStream); - return process.StandardOutput.BaseStream; - } + return process.StandardOutput.BaseStream; } public FFmpegService(ILogger logger, IConfiguration configuration) @@ -101,14 +97,7 @@ public class FFmpegService _fFmpegPath = configuration["files:ffmpeg:value"]; _fFmpegArgs = configuration["files:ffmpeg:args"] ?? "-i - -preset ultrafast -movflags frag_keyframe+empty_moov -f {0} -"; _fFmpegThumbnailsArgs = configuration["files:ffmpeg:thumbnails:args"] ?? "-ss 3 -i \"{0}\" -vf \"thumbnail\" -frames:v 1 -vsync vfr \"{1}\" -y"; - _fFmpegFormats = configuration.GetSection("files:ffmpeg:thumbnails:formats").Get>() ?? new List - { - ".3gp", ".asf", ".avi", ".f4v", - ".fla", ".flv", ".m2ts", ".m4v", - ".mkv", ".mov", ".mp4", ".mpeg", - ".mpg", ".mts", ".ogv", ".svi", - ".vob", ".webm", ".wmv" - }; + _fFmpegFormats = configuration.GetSection("files:ffmpeg:thumbnails:formats").Get>() ?? FileUtility.ExtsVideo; _convertableMedia = (configuration.GetSection("files:ffmpeg:exts").Get() ?? Array.Empty()).ToList(); @@ -190,14 +179,11 @@ public class FFmpegService public async Task CreateThumbnail(string sourcePath, string destPath) { var startInfo = PrepareCommonFFmpeg(); + startInfo.Arguments = string.Format(_fFmpegThumbnailsArgs, sourcePath, destPath); - Process process; - using (process = new Process { StartInfo = startInfo }) - { - process.Start(); - process.WaitForExit(10000); - await ProcessLog(process.StandardError.BaseStream); - } + using var process = Process.Start(startInfo); + + await ProcessLog(process.StandardError.BaseStream); } } diff --git a/products/ASC.Files/Service/Thumbnail/Builder.cs b/products/ASC.Files/Service/Thumbnail/Builder.cs index cf6d9cc5d5..91d9af87f6 100644 --- a/products/ASC.Files/Service/Thumbnail/Builder.cs +++ b/products/ASC.Files/Service/Thumbnail/Builder.cs @@ -80,7 +80,6 @@ public class Builder private readonly PathProvider _pathProvider; private readonly IHttpClientFactory _clientFactory; private readonly ThumbnailSettings _thumbnailSettings; - private readonly TempStream _tempStream; private readonly SocketManager _socketManager; private readonly FFmpegService _fFmpegService; private readonly TempPath _tempPath; @@ -89,6 +88,7 @@ public class Builder { ".bmp", ".gif", ".jpeg", ".jpg", ".pbm", ".png", ".tiff", ".tga", ".webp", }; + public Builder( ThumbnailSettings settings, TenantManager tenantManager, @@ -102,8 +102,7 @@ public class Builder FFmpegService fFmpegService, TempPath tempPath, SocketManager socketManager, - ThumbnailSettings thumbnailSettings, - TempStream tempStream) + ThumbnailSettings thumbnailSettings) { _config = settings; _tenantManager = tenantManager; @@ -118,7 +117,6 @@ public class Builder _tempPath = tempPath; _socketManager = socketManager; _thumbnailSettings = thumbnailSettings; - _tempStream = tempStream; } internal async Task BuildThumbnail(FileData fileData)