-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathimporter.hs
152 lines (118 loc) · 4.62 KB
/
importer.hs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
{-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE Rank2Types #-}
module Importer where
import Control.Applicative (liftA2)
import Control.Lens
import Control.Monad (join)
import Control.Monad.Except (runExceptT, ExceptT, liftIO)
import Data.Aeson (FromJSON (..), Value, withObject, (.:))
import Data.Aeson.Lens
import Data.Aeson.Types (parseMaybe)
import Data.Map
import Data.Maybe (isJust, fromMaybe, catMaybes)
import Data.Monoid ((<>))
import qualified Data.Text as T
import qualified Data.Text.IO as TIO
import Data.Time.Clock (UTCTime)
import Data.Time.Format (parseTimeM, defaultTimeLocale, formatTime)
import qualified Data.Vector as V
import Text.Regex.PCRE
jsonFile :: FilePath
jsonFile = "/Users/kaushik/Developer/src/personal/blog-hakyll/kaushikc-org.ghost.2017-11-05.json"
getJSON :: IO T.Text
getJSON = TIO.readFile jsonFile
data Post = Post {
postId :: Int,
title :: T.Text,
content :: T.Text,
date :: T.Text,
tags :: Maybe [T.Text],
url :: T.Text,
slug :: T.Text,
titleLink :: Maybe T.Text
} deriving Show
bool :: a -> a -> Bool -> a
bool x _ False = x
bool _ y True = y
totuple :: [a] -> Maybe (a,a)
totuple (x : y : _) = Just (x , y)
totuple _ = Nothing
checklinkedpost :: T.Text -> (T.Text , Maybe T.Text)
checklinkedpost s = let pat = "\\[(.*)\\]\\((.*)\\)" :: String
m = T.unpack s =~ pat :: MatchResult String
br :: (T.Text, Maybe T.Text)
br = maybe
(s, Nothing)
(\(a,b) -> (T.pack a, Just (T.pack b)))
(totuple $ mrSubList m)
in
bool (s,Nothing) br (not . Prelude.null $ mrMatch m)
instance FromJSON Post where
parseJSON = withObject "data" (
\o -> do
pid <- o .: "id"
t <- o .: "title"
c <- o .: "markdown"
d <- o .: "published_at"
s <- o .: "slug"
let u = "http://kaushikc.org/" <> s
let (tt, ml) = checklinkedpost t
return $ Post pid tt c d Nothing u s ml)
tpair :: (AsValue t) => T.Text -> T.Text -> Fold t (Int, Value)
tpair l r = folding $ \v ->
do
i <- v ^? key l . _Integral
n <- v ^? key r
pure (i, n)
datestr :: UTCTime -> T.Text
datestr = T.pack . formatTime defaultTimeLocale "%0Y-%0m-%0d"
formatdate :: T.Text -> T.Text
formatdate = maybe ""
datestr
. (parseTimeM True defaultTimeLocale "%0Y-%0m-%0dT%H:%I:%S.000%Z" :: String -> Maybe UTCTime)
. T.unpack
tshow :: Post -> T.Text
tshow p =
"---" <> "\n"
<> "title : " <> title p <> "\n"
<> "published : " <> formatdate (date p) <> "\n"
<> "tags : " <> maybe mempty (T.intercalate ",") (tags p) <> "\n"
<> "link : " <> fromMaybe mempty (titleLink p) <> "\n"
<> "---" <> "\n\n"
<> content p
path :: Post -> FilePath
path p = T.unpack $ "./posts/" <> T.intercalate "-" (T.words $ slug p) <> ".md"
export :: V.Vector Post -> ExceptT String IO ()
export = liftIO . V.mapM_ (liftA2 TIO.writeFile path tshow)
main :: IO ()
main = do
js <- getJSON
let dataL = key "db" . nth 0 . key "data"
let postsL = dataL . key "posts"
let posts :: Maybe (V.Vector Value)
posts = js ^? ( postsL. _Array)
let postsRec :: V.Vector (Maybe Post)
postsRec = maybe V.empty (fmap (parseMaybe parseJSON)) posts
let getTags :: [(Int, Value)]
getTags = js ^.. (key "db" . values . key "data" . key "tags" . values . tpair "id" "name")
let tagsMap :: Map Int Value
tagsMap = fromList getTags
let tag :: Maybe Int -> Maybe Value
tag = maybe Nothing (`Data.Map.lookup` tagsMap)
let postTagTuple :: [(Int, Value)]
postTagTuple = js ^.. (key "db" . values . key "data" . key "posts_tags" . values . tpair "post_id" "tag_id")
let postTagsMap :: Map Int [Maybe T.Text]
postTagsMap = (fmap.fmap) (join.fmap (^? _String)) (fromListWith (++) $ fmap (\(k, a) -> (k, pure $ tag $ a ^? _Integral)) postTagTuple)
let populateTags :: Post -> Post
populateTags p = let ts :: Maybe [T.Text]
ts = fmap catMaybes (Data.Map.lookup (postId p) postTagsMap)
islinked :: Bool
islinked = isJust (titleLink p)
in
p {tags = bool ts (("linked" :) <$> ts) islinked}
let postsRecWithTags :: V.Vector (Maybe Post)
postsRecWithTags = V.filter isJust $ (fmap.fmap) populateTags postsRec
e <- runExceptT $ export(fromMaybe V.empty $ sequence postsRecWithTags)
case e of
Right _ -> return ()
Left er -> putStrLn er