aboutsummaryrefslogtreecommitdiff
path: root/compiler/src/Resource.hs
diff options
context:
space:
mode:
Diffstat (limited to 'compiler/src/Resource.hs')
-rw-r--r--compiler/src/Resource.hs105
1 files changed, 60 insertions, 45 deletions
diff --git a/compiler/src/Resource.hs b/compiler/src/Resource.hs
index e134468..e8ca58c 100644
--- a/compiler/src/Resource.hs
+++ b/compiler/src/Resource.hs
@@ -1,7 +1,7 @@
1-- ldgallery - A static generator which turns a collection of tagged 1-- ldgallery - A static generator which turns a collection of tagged
2-- pictures into a searchable web gallery. 2-- pictures into a searchable web gallery.
3-- 3--
4-- Copyright (C) 2019-2020 Pacien TRAN-GIRARD 4-- Copyright (C) 2019-2022 Pacien TRAN-GIRARD
5-- 5--
6-- This program is free software: you can redistribute it and/or modify 6-- This program is free software: you can redistribute it and/or modify
7-- it under the terms of the GNU Affero General Public License as 7-- it under the terms of the GNU Affero General Public License as
@@ -17,9 +17,15 @@
17-- along with this program. If not, see <https://www.gnu.org/licenses/>. 17-- along with this program. If not, see <https://www.gnu.org/licenses/>.
18 18
19module Resource 19module Resource
20 ( ItemProcessor, ThumbnailProcessor 20 ( ItemProcessor
21 , GalleryItem(..), GalleryItemProps(..), Resolution(..), Resource(..), Thumbnail(..) 21 , GalleryItem(..)
22 , buildGalleryTree, galleryCleanupResourceDir 22 , GalleryItemProps(..)
23 , Resolution(..)
24 , Resource(..)
25 , Thumbnail(..)
26 , buildGalleryTree
27 , galleryCleanupResourceDir
28 , flattenGalleryTree
23 ) where 29 ) where
24 30
25 31
@@ -29,15 +35,16 @@ import Data.List.Ordered (minusBy)
29import Data.Char (toLower) 35import Data.Char (toLower)
30import Data.Maybe (mapMaybe, fromMaybe) 36import Data.Maybe (mapMaybe, fromMaybe)
31import Data.Function ((&)) 37import Data.Function ((&))
38import Data.Functor ((<&>))
32import qualified Data.Set as Set 39import qualified Data.Set as Set
33import Data.Text (pack) 40import Data.Text (pack, unpack, breakOn)
34import Data.Time.Clock (UTCTime) 41import Data.Time.Clock (UTCTime)
35import Data.Time.LocalTime (ZonedTime, utc, utcToZonedTime, zonedTimeToUTC) 42import Data.Time.LocalTime (ZonedTime, utc, utcToZonedTime, zonedTimeToUTC)
36import Data.Time.Format (formatTime, defaultTimeLocale) 43import Data.Time.Format (formatTime, parseTimeM, defaultTimeLocale)
37import Safe.Foldable (maximumByMay) 44import Safe.Foldable (maximumByMay)
38 45
39import GHC.Generics (Generic) 46import GHC.Generics (Generic)
40import Data.Aeson (ToJSON, genericToJSON, genericToEncoding) 47import Data.Aeson (ToJSON, FromJSON, genericToJSON, genericToEncoding, genericParseJSON)
41import qualified Data.Aeson as JSON 48import qualified Data.Aeson as JSON
42 49
43import Files 50import Files
@@ -49,7 +56,7 @@ encodingOptions :: JSON.Options
49encodingOptions = JSON.defaultOptions 56encodingOptions = JSON.defaultOptions
50 { JSON.fieldLabelModifier = map toLower 57 { JSON.fieldLabelModifier = map toLower
51 , JSON.constructorTagModifier = map toLower 58 , JSON.constructorTagModifier = map toLower
52 , JSON.sumEncoding = JSON.defaultTaggedObject 59 , JSON.sumEncoding = JSON.TaggedObject
53 { JSON.tagFieldName = "type" 60 { JSON.tagFieldName = "type"
54 , JSON.contentsFieldName = "contents" 61 , JSON.contentsFieldName = "contents"
55 } 62 }
@@ -69,12 +76,25 @@ instance ToJSON Resource where
69 where 76 where
70 timestamp = formatTime defaultTimeLocale "%s" modTime 77 timestamp = formatTime defaultTimeLocale "%s" modTime
71 78
79instance FromJSON Resource where
80 parseJSON = JSON.withText "Resource" (unpackRes . breakOn "?")
81 where
82 unpackRes (resPathStr, modTimeStr) =
83 Resource (fromWebPath $ unpack resPathStr)
84 <$> parseTimeM True defaultTimeLocale "?%s" (unpack modTimeStr)
85
72 86
73data GalleryItemProps = 87data GalleryItemProps =
74 Directory { items :: [GalleryItem] } 88 Directory { items :: [GalleryItem] }
75 | Picture 89 | Picture
76 { resource :: Resource 90 { resource :: Resource
77 , resolution :: Resolution } 91 , resolution :: Resolution }
92 | PlainText { resource :: Resource }
93 | Markdown { resource :: Resource }
94 | PDF { resource :: Resource }
95 | EPUB { resource :: Resource }
96 | Video { resource :: Resource }
97 | Audio { resource :: Resource }
78 | Other { resource :: Resource } 98 | Other { resource :: Resource }
79 deriving (Generic, Show) 99 deriving (Generic, Show)
80 100
@@ -82,15 +102,14 @@ instance ToJSON GalleryItemProps where
82 toJSON = genericToJSON encodingOptions 102 toJSON = genericToJSON encodingOptions
83 toEncoding = genericToEncoding encodingOptions 103 toEncoding = genericToEncoding encodingOptions
84 104
105instance FromJSON GalleryItemProps where
106 parseJSON = genericParseJSON encodingOptions
107
85 108
86data Thumbnail = Thumbnail 109data Thumbnail = Thumbnail
87 { resource :: Resource 110 { resource :: Resource
88 , resolution :: Resolution 111 , resolution :: Resolution
89 } deriving (Generic, Show) 112 } deriving (Generic, Show, ToJSON, FromJSON)
90
91instance ToJSON Thumbnail where
92 toJSON = genericToJSON encodingOptions
93 toEncoding = genericToEncoding encodingOptions
94 113
95 114
96data GalleryItem = GalleryItem 115data GalleryItem = GalleryItem
@@ -101,49 +120,49 @@ data GalleryItem = GalleryItem
101 , path :: Path 120 , path :: Path
102 , thumbnail :: Maybe Thumbnail 121 , thumbnail :: Maybe Thumbnail
103 , properties :: GalleryItemProps 122 , properties :: GalleryItemProps
104 } deriving (Generic, Show) 123 } deriving (Generic, Show, ToJSON, FromJSON)
105
106instance ToJSON GalleryItem where
107 toJSON = genericToJSON encodingOptions
108 toEncoding = genericToEncoding encodingOptions
109 124
110 125
111type ItemProcessor = Path -> IO GalleryItemProps 126type ItemProcessor a =
112type ThumbnailProcessor = Path -> IO (Maybe Thumbnail) 127 Path -- Item path
128 -> Path -- Resource Path
129 -> IO a
113 130
114 131
115buildGalleryTree :: 132buildGalleryTree ::
116 ItemProcessor -> ThumbnailProcessor -> TagsFromDirectoriesConfig 133 ItemProcessor GalleryItemProps -> ItemProcessor (Maybe Thumbnail) -> TagsFromDirectoriesConfig
117 -> InputTree -> IO GalleryItem 134 -> InputTree -> IO GalleryItem
118buildGalleryTree processItem processThumbnail tagsFromDirsConfig inputTree = 135buildGalleryTree processItem processThumbnail tagsFromDirsConfig =
119 mkGalleryItem [] inputTree 136 mkGalleryItem []
120 where 137 where
121 mkGalleryItem :: [Tag] -> InputTree -> IO GalleryItem 138 mkGalleryItem :: [Tag] -> InputTree -> IO GalleryItem
122 mkGalleryItem inheritedTags InputFile{path, modTime, sidecar} = 139 mkGalleryItem inheritedTags InputFile{path, modTime, sidecar, thumbnailPath} =
123 do 140 do
124 properties <- processItem path 141 let itemPath = "/" /> path
125 processedThumbnail <- processThumbnail path 142 properties <- processItem itemPath path
143 processedThumbnail <- processThumbnail itemPath (thumbnailPath ?? path)
126 return GalleryItem 144 return GalleryItem
127 { title = Input.title sidecar ?? fileName path ?? "" 145 { title = Input.title sidecar ?? fileName path ?? ""
128 , datetime = Input.datetime sidecar ?? toZonedTime modTime 146 , datetime = Input.datetime sidecar ?? toZonedTime modTime
129 , description = Input.description sidecar ?? "" 147 , description = Input.description sidecar ?? ""
130 , tags = unique ((Input.tags sidecar ?? []) ++ inheritedTags ++ parentDirTags path) 148 , tags = unique ((Input.tags sidecar ?? []) ++ inheritedTags ++ parentDirTags path)
131 , path = "/" /> path 149 , path = itemPath
132 , thumbnail = processedThumbnail 150 , thumbnail = processedThumbnail
133 , properties = properties } 151 , properties = properties }
134 152
135 mkGalleryItem inheritedTags InputDir{path, modTime, sidecar, dirThumbnailPath, items} = 153 mkGalleryItem inheritedTags InputDir{path, modTime, sidecar, thumbnailPath, items} =
136 do 154 do
155 let itemPath = "/" /> path
137 let dirTags = (Input.tags sidecar ?? []) ++ inheritedTags 156 let dirTags = (Input.tags sidecar ?? []) ++ inheritedTags
138 processedItems <- parallel $ map (mkGalleryItem dirTags) items 157 processedItems <- parallel $ map (mkGalleryItem dirTags) items
139 processedThumbnail <- maybeThumbnail dirThumbnailPath 158 processedThumbnail <- maybeThumbnail itemPath thumbnailPath
140 return GalleryItem 159 return GalleryItem
141 { title = Input.title sidecar ?? fileName path ?? "" 160 { title = Input.title sidecar ?? fileName path ?? ""
142 , datetime = Input.datetime sidecar ?? mostRecentModTime processedItems 161 , datetime = Input.datetime sidecar ?? mostRecentModTime processedItems
143 ?? toZonedTime modTime 162 ?? toZonedTime modTime
144 , description = Input.description sidecar ?? "" 163 , description = Input.description sidecar ?? ""
145 , tags = unique (aggregateTags processedItems ++ parentDirTags path) 164 , tags = unique (aggregateTags processedItems ++ parentDirTags path)
146 , path = "/" /> path 165 , path = itemPath
147 , thumbnail = processedThumbnail 166 , thumbnail = processedThumbnail
148 , properties = Directory processedItems } 167 , properties = Directory processedItems }
149 168
@@ -161,15 +180,15 @@ buildGalleryTree processItem processThumbnail tagsFromDirsConfig inputTree =
161 & map (prefix tagsFromDirsConfig ++) 180 & map (prefix tagsFromDirsConfig ++)
162 181
163 aggregateTags :: [GalleryItem] -> [Tag] 182 aggregateTags :: [GalleryItem] -> [Tag]
164 aggregateTags = concatMap (\item -> tags (item::GalleryItem)) 183 aggregateTags = concatMap Resource.tags
165 184
166 maybeThumbnail :: Maybe Path -> IO (Maybe Thumbnail) 185 maybeThumbnail :: Path -> Maybe Path -> IO (Maybe Thumbnail)
167 maybeThumbnail Nothing = return Nothing 186 maybeThumbnail _ Nothing = return Nothing
168 maybeThumbnail (Just thumbnailPath) = processThumbnail thumbnailPath 187 maybeThumbnail itemPath (Just thumbnailPath) = processThumbnail itemPath thumbnailPath
169 188
170 mostRecentModTime :: [GalleryItem] -> Maybe ZonedTime 189 mostRecentModTime :: [GalleryItem] -> Maybe ZonedTime
171 mostRecentModTime = 190 mostRecentModTime =
172 maximumByMay comparingTime . map (datetime::(GalleryItem -> ZonedTime)) 191 maximumByMay comparingTime . map Resource.datetime
173 192
174 comparingTime :: ZonedTime -> ZonedTime -> Ordering 193 comparingTime :: ZonedTime -> ZonedTime -> Ordering
175 comparingTime l r = compare (zonedTimeToUTC l) (zonedTimeToUTC r) 194 comparingTime l r = compare (zonedTimeToUTC l) (zonedTimeToUTC r)
@@ -186,7 +205,7 @@ flattenGalleryTree simple = [simple]
186 205
187galleryOutputDiff :: GalleryItem -> FSNode -> [Path] 206galleryOutputDiff :: GalleryItem -> FSNode -> [Path]
188galleryOutputDiff resources ref = 207galleryOutputDiff resources ref =
189 (filesystemPaths ref) \\ (compiledPaths $ flattenGalleryTree resources) 208 filesystemPaths ref \\ compiledPaths (flattenGalleryTree resources)
190 where 209 where
191 filesystemPaths :: FSNode -> [Path] 210 filesystemPaths :: FSNode -> [Path]
192 filesystemPaths = map Files.path . tail . flattenDir 211 filesystemPaths = map Files.path . tail . flattenDir
@@ -201,15 +220,11 @@ galleryOutputDiff resources ref =