예제 #1
0
        /// <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);
        }
예제 #2
0
        // 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);
        }
예제 #3
0
        /// <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
                       ));
        }
예제 #4
0
        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);
        }
예제 #5
0
        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();
        }
예제 #6
0
        /// <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());
        }
예제 #7
0
        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
            });
        }
예제 #8
0
        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);
        }
예제 #10
0
        /// <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);
        }
예제 #11
0
        /// <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);
            }
        }
예제 #12
0
        // 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));
        }
예제 #13
0
        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));
        }
예제 #14
0
        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));
        }
예제 #15
0
        /// <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);
        }
예제 #16
0
        public void FilenamesHelper_GetParentPathSubDir()
        {
            var result = FilenamesHelper.GetParentPath("/sub/yes.jpg");

            Assert.AreEqual("/sub", result);
        }