diff options
Diffstat (limited to 'compiler/src/Resource.hs')
-rw-r--r-- | compiler/src/Resource.hs | 105 |
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 | ||
19 | module Resource | 19 | module 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) | |||
29 | import Data.Char (toLower) | 35 | import Data.Char (toLower) |
30 | import Data.Maybe (mapMaybe, fromMaybe) | 36 | import Data.Maybe (mapMaybe, fromMaybe) |
31 | import Data.Function ((&)) | 37 | import Data.Function ((&)) |
38 | import Data.Functor ((<&>)) | ||
32 | import qualified Data.Set as Set | 39 | import qualified Data.Set as Set |
33 | import Data.Text (pack) | 40 | import Data.Text (pack, unpack, breakOn) |
34 | import Data.Time.Clock (UTCTime) | 41 | import Data.Time.Clock (UTCTime) |
35 | import Data.Time.LocalTime (ZonedTime, utc, utcToZonedTime, zonedTimeToUTC) | 42 | import Data.Time.LocalTime (ZonedTime, utc, utcToZonedTime, zonedTimeToUTC) |
36 | import Data.Time.Format (formatTime, defaultTimeLocale) | 43 | import Data.Time.Format (formatTime, parseTimeM, defaultTimeLocale) |
37 | import Safe.Foldable (maximumByMay) | 44 | import Safe.Foldable (maximumByMay) |
38 | 45 | ||
39 | import GHC.Generics (Generic) | 46 | import GHC.Generics (Generic) |
40 | import Data.Aeson (ToJSON, genericToJSON, genericToEncoding) | 47 | import Data.Aeson (ToJSON, FromJSON, genericToJSON, genericToEncoding, genericParseJSON) |
41 | import qualified Data.Aeson as JSON | 48 | import qualified Data.Aeson as JSON |
42 | 49 | ||
43 | import Files | 50 | import Files |
@@ -49,7 +56,7 @@ encodingOptions :: JSON.Options | |||
49 | encodingOptions = JSON.defaultOptions | 56 | encodingOptions = 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 | ||
79 | instance 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 | ||
73 | data GalleryItemProps = | 87 | data 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 | ||
105 | instance FromJSON GalleryItemProps where | ||
106 | parseJSON = genericParseJSON encodingOptions | ||
107 | |||
85 | 108 | ||
86 | data Thumbnail = Thumbnail | 109 | data 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 | |||
91 | instance ToJSON Thumbnail where | ||
92 | toJSON = genericToJSON encodingOptions | ||
93 | toEncoding = genericToEncoding encodingOptions | ||
94 | 113 | ||
95 | 114 | ||
96 | data GalleryItem = GalleryItem | 115 | data 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 | |||
106 | instance ToJSON GalleryItem where | ||
107 | toJSON = genericToJSON encodingOptions | ||
108 | toEncoding = genericToEncoding encodingOptions | ||
109 | 124 | ||
110 | 125 | ||
111 | type ItemProcessor = Path -> IO GalleryItemProps | 126 | type ItemProcessor a = |
112 | type ThumbnailProcessor = Path -> IO (Maybe Thumbnail) | 127 | Path -- Item path |
128 | -> Path -- Resource Path | ||
129 | -> IO a | ||
113 | 130 | ||
114 | 131 | ||
115 | buildGalleryTree :: | 132 | buildGalleryTree :: |
116 | ItemProcessor -> ThumbnailProcessor -> TagsFromDirectoriesConfig | 133 | ItemProcessor GalleryItemProps -> ItemProcessor (Maybe Thumbnail) -> TagsFromDirectoriesConfig |
117 | -> InputTree -> IO GalleryItem | 134 | -> InputTree -> IO GalleryItem |
118 | buildGalleryTree processItem processThumbnail tagsFromDirsConfig inputTree = | 135 | buildGalleryTree 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 | ||
187 | galleryOutputDiff :: GalleryItem -> FSNode -> [Path] | 206 | galleryOutputDiff :: GalleryItem -> FSNode -> [Path] |
188 | galleryOutputDiff resources ref = | 207 | galleryOutputDiff 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 = | |||