/// <summary> /// Show previous en next items in the folder view. /// There is equivalent class for prev next in the display view /// </summary> /// <param name="currentFolder">subPath style</param> /// <returns>relative object</returns> public RelativeObjects GetNextPrevInFolder(string currentFolder) { if (currentFolder != "/") { PathHelper.RemoveLatestSlash(currentFolder); } // We use breadcrumbs to get the parent folder var parentFolderPath = FilenamesHelper.GetParentPath(currentFolder); var itemsInSubFolder = QueryGetNextPrevInFolder(parentFolderPath); var photoIndexOfSubFolder = itemsInSubFolder.FindIndex(p => p.FilePath == currentFolder); var relativeObject = new RelativeObjects(); if (photoIndexOfSubFolder != itemsInSubFolder.Count - 1 && currentFolder != "/") { // currentFolder != "/" >= on the home folder you will automatically go to a subfolder relativeObject.NextFilePath = itemsInSubFolder[photoIndexOfSubFolder + 1]?.FilePath; relativeObject.NextHash = itemsInSubFolder[photoIndexOfSubFolder + 1]?.FileHash; } if (photoIndexOfSubFolder >= 1) { relativeObject.PrevFilePath = itemsInSubFolder[photoIndexOfSubFolder - 1]?.FilePath; relativeObject.PrevHash = itemsInSubFolder[photoIndexOfSubFolder - 1]?.FileHash; } return(relativeObject); }
// used by the html generator public List <FileIndexItem> ReadExifAndXmpFromFileAddFilePathHash(List <string> subPathList, List <string> fileHashes = null) { var fileIndexList = new List <FileIndexItem>(); for (int i = 0; i < subPathList.Count; i++) { var subPath = subPathList[i]; var returnItem = ReadExifAndXmpFromFile(subPath); var imageFormat = ExtensionRolesHelper.GetImageFormat(_iStorage.ReadStream(subPath, 50)); returnItem.ImageFormat = imageFormat; returnItem.FileName = Path.GetFileName(subPath); returnItem.IsDirectory = false; returnItem.Status = FileIndexItem.ExifStatus.Ok; returnItem.ParentDirectory = FilenamesHelper.GetParentPath(subPath); if (fileHashes == null || fileHashes.Count <= i) { returnItem.FileHash = new FileHash(_iStorage).GetHashCode(subPath).Key; } else { returnItem.FileHash = fileHashes[i]; } fileIndexList.Add(returnItem); } return(fileIndexList); }
/// <summary> /// Get the collections items when preflighting /// Returns as Tuple /// item1: inputFileSubPaths, toFileSubPaths /// item2: list of fileIndex Results (which contains only error cases) /// </summary> /// <param name="inputFileSubPaths">from where to copy (file or folder)</param> /// <param name="toFileSubPaths">copy to (file or folder)</param> /// <param name="fileIndexResultsList">results list</param> /// <param name="collections">enable file collections</param> /// <returns>inputFileSubPaths list, toFileSubPaths list and fileIndexResultsList</returns> private Tuple <Tuple <string[], string[]>, List <FileIndexItem> > CollectionAddPreflight( IReadOnlyList <string> inputFileSubPaths, IReadOnlyList <string> toFileSubPaths, List <FileIndexItem> fileIndexResultsList, bool collections) { if (!collections) { return(new Tuple <Tuple <string[], string[]>, List <FileIndexItem> >( new Tuple <string[], string[]>(inputFileSubPaths.ToArray(), toFileSubPaths.ToArray()), fileIndexResultsList )); } var inputCollectionFileSubPaths = new List <string>(); var toCollectionFileSubPaths = new List <string>(); for (var i = 0; i < inputFileSubPaths.Count; i++) { // When the input is a folder, just copy the array if (_iStorage.ExistFolder(inputFileSubPaths[i])) { inputCollectionFileSubPaths.Add(inputFileSubPaths[i]); toCollectionFileSubPaths.Add(toFileSubPaths[i]); continue; } // when it is a file update the 'to paths' var collectionPaths = _query.SingleItem(inputFileSubPaths[i], null, true, false).FileIndexItem.CollectionPaths; inputCollectionFileSubPaths.AddRange(collectionPaths); for (var j = 0; j < collectionPaths.Count; j++) { var collectionItem = collectionPaths[j]; // When moving to a folder if (_iStorage.ExistFolder(toFileSubPaths[i])) { toCollectionFileSubPaths.Add(toFileSubPaths[i]); continue; } var extensionWithoutDot = FilenamesHelper.GetFileExtensionWithoutDot(collectionItem); // when rename-ing the current file, but the other ones are implicit copied if (j == 0) { extensionWithoutDot = FilenamesHelper.GetFileExtensionWithoutDot(toFileSubPaths[i]); } // Rename other sidecar files // From file to Deleted var parentFolder = FilenamesHelper.GetParentPath(toFileSubPaths[i]); var baseName = FilenamesHelper.GetFileNameWithoutExtension(toFileSubPaths[i]); toCollectionFileSubPaths.Add($"{parentFolder}/{baseName}.{extensionWithoutDot}"); } } return(new Tuple <Tuple <string[], string[]>, List <FileIndexItem> >( new Tuple <string[], string[]>(inputCollectionFileSubPaths.ToArray(), toCollectionFileSubPaths.ToArray()), fileIndexResultsList )); }
internal async Task <List <string> > AddParentCacheIfNotExistAsync(IEnumerable <string> updatedPaths) { var parentDirectoryList = new HashSet <string>(); foreach (var path in updatedPaths) { parentDirectoryList.Add(FilenamesHelper.GetParentPath(path)); } var shouldAddParentDirectoriesToCache = parentDirectoryList.Where(parentDirectory => !_query.CacheGetParentFolder(parentDirectory).Item1).ToList(); if (!shouldAddParentDirectoriesToCache.Any()) { return(new List <string>()); } var databaseQueryResult = await _query.GetAllObjectsAsync(shouldAddParentDirectoriesToCache); _logger.LogInformation("[AddParentCacheIfNotExist] files added to cache " + string.Join(",", shouldAddParentDirectoriesToCache)); foreach (var directory in shouldAddParentDirectoriesToCache) { var byDirectory = databaseQueryResult.Where(p => p.ParentDirectory == directory).ToList(); _query.AddCacheParentItem(directory, byDirectory); } return(shouldAddParentDirectoriesToCache); }
private async Task LoopOverSidecarFiles(List <string> subPaths) { var parentDirectories = new HashSet <string>(); var xmpSubPaths = subPaths .Where(ExtensionRolesHelper.IsExtensionSidecar).ToList(); foreach (var xmpPath in xmpSubPaths) { parentDirectories.Add(FilenamesHelper.GetParentPath(xmpPath)); } var itemsInDirectories = new HashSet <FileIndexItem>( await _query.GetAllFilesAsync(parentDirectories.ToList())); // that is an filepath without extension var collectionPath = xmpSubPaths.Select(singlePath => $"{FilenamesHelper.GetParentPath(singlePath)}/" + FilenamesHelper.GetFileNameWithoutExtension(singlePath)).ToList(); foreach (var item in itemsInDirectories) { foreach (var singleCollectionPath in collectionPath) { if (item.FilePath.StartsWith(singleCollectionPath) && !ExtensionRolesHelper.IsExtensionSidecar(item.FilePath)) { item.RemoveSidecarExtension("xmp"); await _query.UpdateItemAsync(item); } } } Console.WriteLine(); }
/// <summary> /// Get the output of structure applied on the storage /// With the DateTime and fileNameBase applied /// </summary> /// <param name="parsedStructuredList">parsed object, only needed to apply on the storage</param> /// <returns>string with subPath</returns> private string ApplyStructureRangeToStorage(List <List <StructureRange> > parsedStructuredList) { var parentFolderBuilder = new StringBuilder(); foreach (var subStructureItem in parsedStructuredList) { var currentChildFolderBuilder = new StringBuilder(); currentChildFolderBuilder.Append("/"); foreach (var structureItem in subStructureItem) { currentChildFolderBuilder.Append(structureItem.Output); } var parentFolderSubPath = FilenamesHelper.GetParentPath(parentFolderBuilder.ToString()); var existParentFolder = _storage.ExistFolder(parentFolderSubPath); // default situation without asterisk or child directory is NOT found if (!currentChildFolderBuilder.ToString().Contains("*") || !existParentFolder) { var currentChildFolderRemovedAsterisk = RemoveAsteriskFromString(currentChildFolderBuilder); parentFolderBuilder.Append(currentChildFolderRemovedAsterisk); continue; } parentFolderBuilder = MatchChildDirectories(parentFolderBuilder, currentChildFolderBuilder); } return(parentFolderBuilder.ToString()); }
private async Task FromFileToDeleted(string inputFileSubPath, string toFileSubPath, List <FileIndexItem> fileIndexResultsList, List <FileIndexItem> fileIndexItems, DetailView detailView) { // when trying to rename something wrongs var fileName = FilenamesHelper.GetFileName(toFileSubPath); if (!FilenamesHelper.IsValidFileName(fileName)) { fileIndexResultsList.Add(new FileIndexItem { Status = FileIndexItem.ExifStatus.OperationNotSupported }); return; //next } // from/input cache should be cleared var inputParentSubFolder = FilenamesHelper.GetParentPath(inputFileSubPath); _query.RemoveCacheParentItem(inputParentSubFolder); var toParentSubFolder = FilenamesHelper.GetParentPath(toFileSubPath); if (string.IsNullOrEmpty(toParentSubFolder)) { toParentSubFolder = "/"; } // clear cache (to FileSubPath parents) _query.RemoveCacheParentItem(toParentSubFolder); // Check if the parent folder exist in the database await _query.AddParentItemsAsync(toParentSubFolder); // Save in database before change on disk await SaveToDatabaseAsync(fileIndexItems, fileIndexResultsList, detailView, toFileSubPath); // add folder to file system if (!_iStorage.ExistFolder(toParentSubFolder)) { _iStorage.CreateDirectory(toParentSubFolder); fileIndexResultsList.Add(new FileIndexItem(toParentSubFolder) { Status = FileIndexItem.ExifStatus.Ok }); } _iStorage.FileMove(inputFileSubPath, toFileSubPath); MoveSidecarFile(inputFileSubPath, toFileSubPath); // when renaming a folder it should warn the UI that it should remove the source item fileIndexResultsList.Add(new FileIndexItem(inputFileSubPath) { Status = FileIndexItem.ExifStatus.NotFoundSourceMissing }); }
public Task <List <FileIndexItem> > GetObjectsByFilePathCollectionAsync(List <string> filePathList) { var result = new List <FileIndexItem>(); foreach (var path in filePathList) { var fileNameWithoutExtension = FilenamesHelper.GetFileNameWithoutExtension(path); result.AddRange(_fakeContext.Where(p => p.ParentDirectory == FilenamesHelper.GetParentPath(path) && p.FileName.StartsWith(fileNameWithoutExtension))); } return(Task.FromResult(result)); }
/// <summary> /// Uses Cache /// </summary> /// <param name="inputFilePaths">list of paths</param> /// <param name="collections">uses collections </param> /// <returns>list with items</returns> public async Task <List <FileIndexItem> > GetObjectsByFilePathAsync(List <string> inputFilePaths, bool collections) { var resultFileIndexItemsList = new List <FileIndexItem>(); var toQueryPaths = new List <string>(); foreach (var path in inputFilePaths) { var parentPath = FilenamesHelper.GetParentPath(path); var(success, cachedResult) = CacheGetParentFolder(parentPath); List <FileIndexItem> item = null; switch (collections) { case false: if (!success) { break; } item = cachedResult.Where(p => p.ParentDirectory == parentPath && p.FileName == FilenamesHelper.GetFileName(path)).ToList(); break; case true: if (!success) { break; } item = cachedResult.Where(p => p.ParentDirectory == parentPath && p.FileCollectionName == FilenamesHelper.GetFileNameWithoutExtension(path)).ToList(); break; } if (!success || !item.Any()) { toQueryPaths.Add(path); continue; } resultFileIndexItemsList.AddRange(item); } var fileIndexItemsList = await GetObjectsByFilePathQuery(toQueryPaths.ToArray(), collections); resultFileIndexItemsList.AddRange(fileIndexItemsList); return(resultFileIndexItemsList); }
/// <summary> /// Sidecar files don't have an own item, but there referenced by file items /// in the method xmp files are added to the AddSidecarExtension list. /// </summary> /// <param name="xmpSubPath">sidecar item</param> /// <returns>completed task</returns> public async Task UpdateSidecarFile(string xmpSubPath) { if (!ExtensionRolesHelper.IsExtensionSidecar(xmpSubPath)) { return; } var parentPath = FilenamesHelper.GetParentPath(xmpSubPath); var fileNameWithoutExtension = FilenamesHelper.GetFileNameWithoutExtension(xmpSubPath); var directoryWithFileIndexItems = (await _query.GetAllFilesAsync(parentPath)).Where( p => p.ParentDirectory == parentPath && p.FileCollectionName == fileNameWithoutExtension).ToList(); await UpdateSidecarFile(xmpSubPath, directoryWithFileIndexItems); }
/// <summary> /// Extractes a <c>tar</c> archive to the specified directory. /// </summary> /// <param name="stream">The <i>.tar</i> to extract.</param> /// <param name="outputDir">Output directory to write the files.</param> public void ExtractTar(Stream stream, string outputDir) { var buffer = new byte[100]; while (true) { stream.Read(buffer, 0, 100); var name = Encoding.ASCII.GetString(buffer).Trim('\0'); if (string.IsNullOrEmpty(name) || stream.Position > stream.Length) { break; } stream.Seek(24, SeekOrigin.Current); stream.Read(buffer, 0, 12); var size = Convert.ToInt64(Encoding.UTF8.GetString(buffer, 0, 12).Trim('\0').Trim(), 8); stream.Seek(376L, SeekOrigin.Current); var output = $"{outputDir}/{name}"; if (!_storage.ExistFolder(FilenamesHelper.GetParentPath(output))) { _storage.CreateDirectory(FilenamesHelper.GetParentPath(output)); } if (!name.EndsWith("/", StringComparison.InvariantCulture)) { var str = new MemoryStream(); var buf = new byte[size]; stream.Read(buf, 0, buf.Length); str.Write(buf, 0, buf.Length); _storage.WriteStreamOpenOrCreate(str, output); } var pos = stream.Position; var offset = 512 - (pos % 512); if (offset == 512) { offset = 0; } stream.Seek(offset, SeekOrigin.Current); } }
// For displaying single photo's // Display feature only?! // input: Name of item by db style path // With Caching feature :) /// <summary> /// SingleItemPath do the query for singleitem + return detailview object /// </summary> /// <param name="singleItemDbPath"></param> /// <param name="colorClassActiveList">list of colorclasses to show, default show all</param> /// <param name="enableCollections">enable collections feature > default true</param> /// <param name="hideDeleted">do not show deleted files > default true</param> /// <returns>view object to show on the page</returns> public DetailView SingleItem( string singleItemDbPath, List <ColorClassParser.Color> colorClassActiveList = null, bool enableCollections = true, bool hideDeleted = true, SortType sort = SortType.FileName) { if (string.IsNullOrWhiteSpace(singleItemDbPath)) { return(null); } var parentFolder = FilenamesHelper.GetParentPath(singleItemDbPath); var fileIndexItemsList = DisplayFileFolders( parentFolder, null, false, false).ToList(); return(SingleItem( fileIndexItemsList, singleItemDbPath, colorClassActiveList, enableCollections, hideDeleted, sort)); }
internal string GetParentDirectoryFromRequestHeader() { var to = Request.Headers["to"].ToString(); if (to == "/") { return("/"); } // only used for direct import if (_iStorage.ExistFolder(FilenamesHelper.GetParentPath(to)) && FilenamesHelper.IsValidFileName(FilenamesHelper.GetFileName(to))) { Request.Headers["filename"] = FilenamesHelper.GetFileName(to); return(FilenamesHelper.GetParentPath(PathHelper.RemoveLatestSlash(to))); } // ReSharper disable once ConvertIfStatementToReturnStatement if (!_iStorage.ExistFolder(PathHelper.RemoveLatestSlash(to))) { return(null); } return(PathHelper.RemoveLatestSlash(to)); }
private static IOrderedQueryable <FileIndexItem> GetObjectsByFilePathCollectionQuery(ApplicationDbContext context, IEnumerable <string> filePathList) { var predicates = new List <Expression <Func <FileIndexItem, bool> > >(); // ReSharper disable once LoopCanBeConvertedToQuery foreach (var path in filePathList) { var fileNameWithoutExtension = FilenamesHelper.GetFileNameWithoutExtension(path); if (string.IsNullOrEmpty(FilenamesHelper.GetFileExtensionWithoutDot(path))) { predicates.Add(p => p.ParentDirectory == FilenamesHelper.GetParentPath(path) && p.FileName == fileNameWithoutExtension); continue; } predicates.Add(p => p.ParentDirectory == FilenamesHelper.GetParentPath(path) && p.FileName.StartsWith(fileNameWithoutExtension + ".")); } var predicate = PredicateBuilder.OrLoop(predicates); return(context.FileIndex.Where(predicate).OrderBy(r => r.FileName)); }
/// <summary> /// fileIndexItemsList, Create an detailView object /// </summary> /// <param name="fileIndexItemsList">list of fileIndexItems</param> /// <param name="singleItemDbPath">database style path</param> /// <param name="colorClassActiveList">list of colorClasses to show, default show all</param> /// <param name="enableCollections">enable collections feature > default true</param> /// <param name="hideDeleted">do not show deleted files > default true</param> /// <returns>view object to show on the page</returns> public DetailView SingleItem( List <FileIndexItem> fileIndexItemsList, string singleItemDbPath, List <ColorClassParser.Color> colorClassActiveList = null, bool enableCollections = true, bool hideDeleted = true, SortType sort = SortType.FileName) { // reject empty requests if (string.IsNullOrWhiteSpace(singleItemDbPath)) { return(null); } var parentFolder = FilenamesHelper.GetParentPath(singleItemDbPath); // RemoveLatestSlash is for '/' folder var fileName = singleItemDbPath.Replace( PathHelper.RemoveLatestSlash(parentFolder) + "/", string.Empty); // Home has no parent, so return a value if (fileName == string.Empty && parentFolder == "/" && GetObjectByFilePath("/") != null) { return(new DetailView { FileIndexItem = GetObjectByFilePath("/"), RelativeObjects = new RelativeObjects(), Breadcrumb = new List <string> { "/" }, ColorClassActiveList = colorClassActiveList, IsDirectory = true, SubPath = "/", Collections = enableCollections }); } var currentFileIndexItem = fileIndexItemsList.FirstOrDefault(p => p.FileName == fileName); // Could be not found or not in directory cache if (currentFileIndexItem == null) { // retry currentFileIndexItem = GetObjectByFilePath(singleItemDbPath); if (currentFileIndexItem == null) { return(null); } AddCacheItem(currentFileIndexItem); } // To know when a file is deleted if (currentFileIndexItem.Tags.Contains("!delete!")) { currentFileIndexItem.Status = FileIndexItem.ExifStatus.Deleted; } if (currentFileIndexItem.IsDirectory == true) { currentFileIndexItem.CollectionPaths = new List <string> { singleItemDbPath }; return(new DetailView { IsDirectory = true, SubPath = singleItemDbPath, FileIndexItem = currentFileIndexItem, Collections = enableCollections, }); } if (currentFileIndexItem.Tags.Contains("!delete!")) { hideDeleted = false; } var fileIndexItemsForPrevNextList = DisplayFileFolders( parentFolder, colorClassActiveList, enableCollections, hideDeleted).ToList(); var itemResult = new DetailView { FileIndexItem = currentFileIndexItem, RelativeObjects = GetNextPrevInSubFolder(currentFileIndexItem, fileIndexItemsForPrevNextList, sort), Breadcrumb = Breadcrumbs.BreadcrumbHelper(singleItemDbPath), ColorClassActiveList = colorClassActiveList, IsDirectory = false, SubPath = singleItemDbPath, Collections = enableCollections }; // First item is current item var collectionPaths = new List <string> { singleItemDbPath }; collectionPaths.AddRange(fileIndexItemsList .Where(p => p.FileCollectionName == currentFileIndexItem.FileCollectionName) .Select(p => p.FilePath)); var collectionPathsHashSet = new HashSet <string>(collectionPaths); itemResult.FileIndexItem.CollectionPaths = collectionPathsHashSet.ToList(); return(itemResult); }
public void FilenamesHelper_GetParentPathSubDir() { var result = FilenamesHelper.GetParentPath("/sub/yes.jpg"); Assert.AreEqual("/sub", result); }