-
Notifications
You must be signed in to change notification settings - Fork 3
/
Items.hs
134 lines (127 loc) · 4.83 KB
/
Items.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
module Items (loadData) where
import Control.Exception.Extra (retry)
import Control.Lens
import Control.Monad (unless)
import Control.Monad.Logger (LoggingT)
import Control.Monad.Trans.Reader (ReaderT)
import Data.ByteString.Lens (unpackedChars)
import Data.Default (def)
import Data.Either (fromRight)
import qualified Data.Text as T
import Data.Text.Lens (unpacked, _Text)
import Data.Traversable (for)
import Database.Persist.Sql (SqlBackend)
import Import
import Model.IsaacPool
import Model.IsaacVersion
import qualified Network.Wreq as W
import qualified Network.Wreq.Session as S
import qualified Text.XML as XML
import Text.XML.Lens (root, el, attr, attributeIs, attributeSatisfies, (...), localName)
import URI.ByteString (parseURI, strictURIParserOptions, pathL, URI(), serializeURIRef')
pools :: [(Text, IsaacPool)]
pools =
[ ("treasure", PoolItemRoom)
, ("shop", PoolShop)
, ("boss", PoolBossRoom)
, ("devil", PoolDevilRoom)
, ("angel", PoolAngelRoom)
, ("secret", PoolSecretRoom)
, ("library", PoolLibrary)
, ("goldenChest", PoolGoldenChest)
, ("redChest", PoolRedChest)
, ("beggar", PoolBeggar)
, ("demonBeggar", PoolDemonBeggar)
, ("curse", PoolCurseRoom)
, ("keyMaster", PoolKeyBeggar)
]
itemsFor :: Text -> Traversal' XML.Document XML.Element
itemsFor name = root . el "ItemPools" ... el "Pool" . attributeIs "Name" name ... el "Item"
items :: Traversal' XML.Document XML.Element
items = root ... filtered ((`elem` ["active", "passive", "familiar"]) . XML.elementName) . attributeSatisfies "description" (not . T.null)
wikiBase :: URI
wikiBase = fromRight (error "wikibase") $ parseURI strictURIParserOptions
"http://bindingofisaacrebirth.gamepedia.com/"
wikiName :: Text -> Int -> Text
wikiName name iid = case name of
"<3" -> "Less_Than_Three"
"1up!" -> "1up!"
"Teleport!" -> "Teleport"
"Odd Mushroom" -> case iid of
120 -> "Odd_Mushroom_(Thin)"
121 -> "Odd_Mushroom_(Large)"
_ -> ""
"PHD" -> "PHD"
"IV Bag" -> "IV_Bag"
"Tooth Picks" -> "Toothpicks"
"Guppy's Hairball" -> "Guppy's_Hair_Ball"
"Humbleing Bundle" -> "Humbling_Bundle"
"SMB Super Fan" -> "SMB_Super_Fan"
"Spiderbaby" -> "Spider_Baby"
"E. Coli" -> "E_Coli"
"BBF" -> "BBF"
"BFFS!" -> "BFFS!"
"Lil Chest" -> "Lil'_Chest"
"GB Bug" -> "GB_Bug"
"PJs" -> "PJs"
"Lil Loki" -> "Lil'_Loki"
"Dark Princes Crown" -> "Dark_Prince's_Crown"
"YO LISTEN!" -> "YO_LISTEN!"
"Buddy in a Box" -> "Buddy_in_a_Box"
"Mr. ME!" -> "Mr._ME!"
_ -> T.replace "_The_" "_the_"
. T.replace "_For_" "_for_"
. T.replace "_Of_" "_of_"
. T.replace "_To_" "_to_"
. T.replace "'S" "'s"
. T.replace " " "_"
. T.toTitle $ name
loadData :: String -> FilePath -> FilePath -> ReaderT SqlBackend (LoggingT IO) ()
loadData ver itemsPath poolsPath = do
Just ver' <- pure $ fromPathPiece @IsaacVersion (_Text # ver)
itemsDoc <- liftIO $ XML.readFile def itemsPath
sess <- liftIO S.newAPISession
parsedItems <- liftIO $
for (itemsDoc ^.. items) $ \item -> do
let name = item ^?! attr "name"
desc = item ^?! attr "description"
iid :: Int
iid = item ^?! attr "id" . unpacked . _Show
itype = item ^. localName
wiki = wikiBase & pathL . unpackedChars . from unpacked <>~ wikiName name iid
wikiS = wiki ^. to serializeURIRef' . unpackedChars
wikiText :: Text
wikiText = wikiS ^. from unpacked
r <- retry 5 $ S.headWith
(W.defaults & W.checkResponse ?~ \_ _ -> return ())
sess
(wiki ^. to serializeURIRef' . unpackedChars)
unless (r ^. W.responseStatus . W.statusCode == 200) (print $ "Invalid wiki: " <> wikiText)
return
Item { _itemVersion = ver'
, _itemIsaacId = iid
, _itemName = name
, _itemDescription = desc
, _itemWiki = if r ^. W.responseStatus . W.statusCode == 200
then wikiText else ""
, _itemRating = 500.1
, _itemVotes = 0
, _itemPools = []
, _itemItype = itype
}
for_ parsedItems $ \parsedItem ->
upsert parsedItem
[ ItemName =. parsedItem ^. itemName
, ItemDescription =. parsedItem ^. itemDescription
, ItemWiki =. parsedItem ^. itemWiki
, ItemItype =. parsedItem ^. itemItype
]
poolsDoc <- liftIO $ XML.readFile def poolsPath
updateWhere [] [ItemPools =. []]
for_ pools $ \(name, pool) ->
forOf_ (itemsFor name) poolsDoc $ \e -> do
let isaacId :: Int
isaacId = e ^?! attr "Id" . unpacked . _Show
Just (Entity k item) <- getBy $ UniqueItem ver' isaacId
replace k (item & itemPools %~ (pool:))
updateWhere [ItemPools ==. []] [ItemPools =. [PoolMISC]]