From 395a76bc4193c0c7182f87778458a68d0079e836 Mon Sep 17 00:00:00 2001 From: pacien Date: Fri, 14 Feb 2020 15:39:56 +0100 Subject: compiler: metadata sidecar for whole directories GitHub: closes #3 --- compiler/src/Compiler.hs | 2 +- compiler/src/Config.hs | 6 +-- compiler/src/Input.hs | 7 +++- compiler/src/Resource.hs | 61 +++++++++++++++--------------- example/readme.md | 2 + example/src/Glacier 3000/_DSC5475.jpg.yaml | 2 - example/src/Glacier 3000/_DSC5542.jpg.yaml | 2 - example/src/Glacier 3000/directory.yaml | 4 ++ example/src/directory.yaml | 1 + example/src/gallery.yaml | 2 - ldgallery.1.md | 29 ++++++++------ 11 files changed, 64 insertions(+), 54 deletions(-) create mode 100644 example/src/Glacier 3000/directory.yaml create mode 100644 example/src/directory.yaml diff --git a/compiler/src/Compiler.hs b/compiler/src/Compiler.hs index 2a0dccc..bfefa63 100644 --- a/compiler/src/Compiler.hs +++ b/compiler/src/Compiler.hs @@ -116,7 +116,7 @@ compileGallery inputDirPath outputDirPath excludedDirs rebuildAll cleanOutput = let itemProc = itemProcessor config cache let thumbnailProc = thumbnailProcessor config cache let galleryBuilder = buildGalleryTree itemProc thumbnailProc (tagsFromDirectories config) - resources <- galleryBuilder (galleryName config) inputTree + resources <- galleryBuilder inputTree when cleanOutput $ galleryCleanupResourceDir resources outputDirPath writeJSON outputIndex resources diff --git a/compiler/src/Config.hs b/compiler/src/Config.hs index 4c9aa40..4826f17 100644 --- a/compiler/src/Config.hs +++ b/compiler/src/Config.hs @@ -33,8 +33,7 @@ import Resource (Resolution(..)) data CompilerConfig = CompilerConfig - { galleryName :: String - , includedDirectories :: [String] + { includedDirectories :: [String] , excludedDirectories :: [String] , includedFiles :: [String] , excludedFiles :: [String] @@ -45,8 +44,7 @@ data CompilerConfig = CompilerConfig instance FromJSON CompilerConfig where parseJSON = withObject "CompilerConfig" $ \v -> CompilerConfig - <$> v .:? "galleryName" .!= "Gallery" - <*> v .:? "includedDirectories" .!= ["*"] + <$> v .:? "includedDirectories" .!= ["*"] <*> v .:? "excludedDirectories" .!= [] <*> v .:? "includedFiles" .!= ["*"] <*> v .:? "excludedFiles" .!= [] diff --git a/compiler/src/Input.hs b/compiler/src/Input.hs index cb837e3..e0fc8ef 100644 --- a/compiler/src/Input.hs +++ b/compiler/src/Input.hs @@ -58,6 +58,7 @@ data InputTree = | InputDir { path :: Path , modTime :: UTCTime + , sidecar :: Sidecar , dirThumbnailPath :: Maybe Path , items :: [InputTree] } deriving Show @@ -79,6 +80,9 @@ emptySidecar = Sidecar sidecarExt :: String sidecarExt = "yaml" +dirSidecar :: String +dirSidecar = "directory." ++ sidecarExt + readSidecarFile :: FilePath -> IO Sidecar readSidecarFile filepath = doesFileExist filepath @@ -107,7 +111,8 @@ readInputTree (AnchoredFSNode anchor root@Dir{}) = mkDirNode root do dirItems <- mapM mkInputNode items modTime <- getModificationTime $ localPath (anchor /> path) - return $ InputDir path modTime (findThumbnail items) (catMaybes dirItems) + sidecar <- readSidecarFile $ localPath (anchor /> path Bool isSidecar Dir{} = False diff --git a/compiler/src/Resource.hs b/compiler/src/Resource.hs index 400e18a..aadf60b 100644 --- a/compiler/src/Resource.hs +++ b/compiler/src/Resource.hs @@ -121,44 +121,52 @@ type ThumbnailProcessor = Path -> IO (Maybe Thumbnail) buildGalleryTree :: ItemProcessor -> ThumbnailProcessor - -> Int -> String -> InputTree -> IO GalleryItem -buildGalleryTree processItem processThumbnail tagsFromDirectories galleryName inputTree = - mkGalleryItem [] inputTree + -> Int -> InputTree -> IO GalleryItem +buildGalleryTree processItem processThumbnail tagsFromDirectories inputTree = + mkGalleryItem [] [] inputTree where - mkGalleryItem :: [String] -> InputTree -> IO GalleryItem - mkGalleryItem parentTitles InputFile{path, modTime, sidecar} = + mkGalleryItem :: [String] -> [Tag] -> InputTree -> IO GalleryItem + mkGalleryItem parentDirs inheritedTags InputFile{path, modTime, sidecar} = do properties <- processItem path processedThumbnail <- processThumbnail path return GalleryItem - { title = fromMeta title $ fromMaybe "" $ fileName path - , datetime = fromMaybe (toZonedTime modTime) (Input.datetime sidecar) - , description = fromMeta description "" - , tags = unique ((fromMeta tags []) ++ implicitParentTags parentTitles) + { title = Input.title sidecar ?? fileName path ?? "" + , datetime = Input.datetime sidecar ?? toZonedTime modTime + , description = Input.description sidecar ?? "" + , tags = unique ((Input.tags sidecar ?? []) ++ inheritedTags ++ parentDirTags parentDirs) , path = "/" /> path , thumbnail = processedThumbnail , properties = properties } - where - fromMeta :: (Sidecar -> Maybe a) -> a -> a - fromMeta get fallback = fromMaybe fallback $ get sidecar - - mkGalleryItem parentTitles InputDir{path, modTime, dirThumbnailPath, items} = + mkGalleryItem parentDirs inheritedTags InputDir{path, modTime, sidecar, dirThumbnailPath, items} = do + let itemsParents = (maybeToList $ fileName path) ++ parentDirs + let dirTags = (Input.tags sidecar ?? []) ++ inheritedTags + processedItems <- parallel $ map (mkGalleryItem itemsParents dirTags) items processedThumbnail <- maybeThumbnail dirThumbnailPath - processedItems <- parallel $ map (mkGalleryItem subItemsParents) items return GalleryItem - { title = fromMaybe galleryName (fileName path) - , datetime = fromMaybe (toZonedTime modTime) (mostRecentModTime processedItems) - , description = "" - , tags = unique (aggregateTags processedItems ++ implicitParentTags parentTitles) + { title = Input.title sidecar ?? fileName path ?? "" + , datetime = Input.datetime sidecar ?? mostRecentModTime processedItems + ?? toZonedTime modTime + , description = Input.description sidecar ?? "" + , tags = unique (aggregateTags processedItems ++ parentDirTags parentDirs) , path = "/" /> path , thumbnail = processedThumbnail , properties = Directory processedItems } - where - subItemsParents :: [String] - subItemsParents = (maybeToList $ fileName path) ++ parentTitles + infixr ?? + (??) :: Maybe a -> a -> a + (??) = flip fromMaybe + + unique :: Ord a => [a] -> [a] + unique = Set.toList . Set.fromList + + parentDirTags :: [String] -> [Tag] + parentDirTags = take tagsFromDirectories + + aggregateTags :: [GalleryItem] -> [Tag] + aggregateTags = concatMap (\item -> tags (item::GalleryItem)) maybeThumbnail :: Maybe Path -> IO (Maybe Thumbnail) maybeThumbnail Nothing = return Nothing @@ -171,15 +179,6 @@ buildGalleryTree processItem processThumbnail tagsFromDirectories galleryName in comparingTime :: ZonedTime -> ZonedTime -> Ordering comparingTime l r = compare (zonedTimeToUTC l) (zonedTimeToUTC r) - aggregateTags :: [GalleryItem] -> [Tag] - aggregateTags = concatMap (\item -> tags (item::GalleryItem)) - - unique :: Ord a => [a] -> [a] - unique = Set.toList . Set.fromList - - implicitParentTags :: [String] -> [Tag] - implicitParentTags = take tagsFromDirectories - toZonedTime :: UTCTime -> ZonedTime toZonedTime = utcToZonedTime utc diff --git a/example/readme.md b/example/readme.md index e455f03..eafdaf5 100644 --- a/example/readme.md +++ b/example/readme.md @@ -14,9 +14,11 @@ Content ├── _DSC8808-1.jpg.yaml -- its associated sidecar metadata file ├── Glacier 3000 -- a directory grouping gallery items │   ├── thumbnail.jpg -- a thumbnail for the "Glacier 3000" directory +│   ├── directory.yaml -- sidecar metadata file for the "Glacier 3000" directory │   ├── _DSC5475.jpg │   ├── _DSC5475.jpg.yaml │   ├── _DSC5542.jpg │   └── _DSC5542.jpg.yaml +├── directory.yaml -- sidecar metadata file for the root directory └── gallery.yaml -- gallery settings file ``` diff --git a/example/src/Glacier 3000/_DSC5475.jpg.yaml b/example/src/Glacier 3000/_DSC5475.jpg.yaml index 3454a68..dfff6e8 100644 --- a/example/src/Glacier 3000/_DSC5475.jpg.yaml +++ b/example/src/Glacier 3000/_DSC5475.jpg.yaml @@ -7,8 +7,6 @@ description: > tags: - photographer.nphilou - - location.switzerland.ormont-dessus - - glacier3000 - time.day - weather.foggy - forest diff --git a/example/src/Glacier 3000/_DSC5542.jpg.yaml b/example/src/Glacier 3000/_DSC5542.jpg.yaml index d174911..f2c6a94 100644 --- a/example/src/Glacier 3000/_DSC5542.jpg.yaml +++ b/example/src/Glacier 3000/_DSC5542.jpg.yaml @@ -7,8 +7,6 @@ description: > tags: - photographer.nphilou - - location.switzerland.ormont-dessus - - glacier3000 - time.day - weather.foggy - catwalk diff --git a/example/src/Glacier 3000/directory.yaml b/example/src/Glacier 3000/directory.yaml new file mode 100644 index 0000000..44674cf --- /dev/null +++ b/example/src/Glacier 3000/directory.yaml @@ -0,0 +1,4 @@ +# The following tags are applied to all items in the directory +tags: + - location.switzerland.ormont-dessus + - glacier3000 diff --git a/example/src/directory.yaml b/example/src/directory.yaml new file mode 100644 index 0000000..ab81bb2 --- /dev/null +++ b/example/src/directory.yaml @@ -0,0 +1 @@ +title: Example gallery diff --git a/example/src/gallery.yaml b/example/src/gallery.yaml index 5efbfef..bef19e0 100644 --- a/example/src/gallery.yaml +++ b/example/src/gallery.yaml @@ -1,6 +1,4 @@ compiler: - galleryName: Example gallery - #includedDirectories: ["*"] #excludedDirectories: [] diff --git a/ldgallery.1.md b/ldgallery.1.md index f071344..17056ce 100644 --- a/ldgallery.1.md +++ b/ldgallery.1.md @@ -2,7 +2,7 @@ pagetitle: User manual - ldgallery title: LDGALLERY(1) ldgallery user manual author: Pacien TRAN-GIRARD, Guillaume FOUET -date: 2020-01-05 (v0.1.0.0-SNAPSHOT) +date: 2020-02-15 (v0.1.0.0-SNAPSHOT) --- @@ -55,7 +55,8 @@ Available options are: # INPUT GALLERY STRUCTURE A gallery source directory contains the gallery items and their sidecar metadata files, optionally grouped inside sub-directories. -Directory thumbnails can be set by placing a picture file named "thumbnail", with any image file extension, inside of it. + +Directory thumbnails can be set by placing a picture file named "thumbnail", with any image file extension, inside of directories. An example input gallery directory structure could be as follows: @@ -65,6 +66,7 @@ An example input gallery directory structure could be as follows: ├── DSC0001.jpg.yaml ---- its associated sidecar metadata file ├── Some directory ------ a directory grouping gallery items │ ├── thumbnail.jpg --- a thumbnail for its parent directory +│ ├── directory.yaml -- directory sidecar metadata file │ ├── DSC0002.jpg │ ├── DSC0002.jpg.yaml │ ├── DSC0003.jpg @@ -73,32 +75,37 @@ An example input gallery directory structure could be as follows: ``` -# ITEM METADATA SIDECAR +# METADATA SIDECAR -Item metadata are read from sidecar files of the same name, with the ".yaml" extension appended. -When a sidecar file is absent or a particular key omitted, values are set as empty or to their fallback value specified below. +File metadata are read from sidecar files of the same name, with the ".yaml" extension appended. Metadata contained within item files themselves (e.g. Exif fields for pictures) are ignored. +Directory metadata are read from sidecar files named "directory.yaml" located within the directory. + +When a sidecar file is absent or a particular key omitted, values are set as empty or to their fallback value specified below. + title -: Title of the item. Defaults to the name of the file. +: Title of the item. + Defaults to the name of the file or directory. datetime -: ISO 8601 zoned date and time. Defaults to the last modification time of the file. +: ISO 8601 zoned date and time. + Defaults to the last modification time of the file itself, + or the most recent modification date of a directory's items. description : Description for the item. tags -: List of tags for the item. Tag groups can be defined using prefixes separated by "." (dot). +: List of tags for the item. + Tag groups can be defined using prefixes separated by "." (dot). + Tags specified in a directory metadata sidecar are applied to all items within that directory. # GALLERY CONFIGURATION The gallery settings reside in a file named "gallery.yaml" located at the root of the gallery's source directory. -compiler.galleryName -: Name of the gallery. Defaults to "Gallery". - compiler.includedDirectories[] : Glob patterns of directory names to include in the gallery. Defaults to ["*"] (matches all directory names). -- cgit v1.2.3