ArtDecoCard.purs 5.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154
  1. module LinkedIn.ArtDecoCard where
  2. import Prelude
  3. import Control.Monad.Maybe.Trans (MaybeT)
  4. import Data.Either (Either(..), hush)
  5. import Data.Generic.Rep (class Generic)
  6. import Data.List.NonEmpty as NEL
  7. import Data.List.Types (NonEmptyList)
  8. import Data.Maybe (Maybe(..), fromJust)
  9. import Data.Show.Generic (genericShow)
  10. import Data.Traversable (traverse)
  11. import Debug (trace)
  12. import Effect (Effect)
  13. import Effect.Exception (try)
  14. import LinkedIn (DetachedNode, toDetached)
  15. import Partial.Unsafe (unsafePartial)
  16. import Web.DOM (Node, ParentNode)
  17. import Web.DOM.Element as E
  18. import Web.DOM.NodeList as NL
  19. import Web.DOM.ParentNode (QuerySelector(..), querySelector, querySelectorAll)
  20. data ArtDecoPvsEntitySubComponents = ArtDecoPvsEntitySubComponents (Maybe (NonEmptyList DetachedNode))
  21. derive instance Generic ArtDecoPvsEntitySubComponents _
  22. instance Show ArtDecoPvsEntitySubComponents where
  23. show = genericShow
  24. data ArtDecoCenterContent = ArtDecoCenterContent (Maybe (NonEmptyList DetachedNode))
  25. derive instance Generic ArtDecoCenterContent _
  26. instance Show ArtDecoCenterContent where
  27. show = genericShow
  28. parseArtDecoCenterContent ∷ Node → Effect (Either String ArtDecoCenterContent)
  29. parseArtDecoCenterContent n = do
  30. list <- queryAndDetachMany ":scope > ul > li" n
  31. pure $ Right (ArtDecoCenterContent (hush list))
  32. data ArtDecoCenterHeader = ArtDecoCenterHeader {
  33. bold :: DetachedNode,
  34. normal :: Maybe DetachedNode,
  35. light :: Maybe (NonEmptyList DetachedNode)
  36. }
  37. derive instance Generic ArtDecoCenterHeader _
  38. instance Show ArtDecoCenterHeader where
  39. show = genericShow
  40. parseArtDecoCenterHeader :: Node -> Effect (Either String ArtDecoCenterHeader)
  41. parseArtDecoCenterHeader n = do
  42. bold <- queryAndDetachOne ":scope div.t-bold > span[aria-hidden=true]" n
  43. normal <- queryAndDetachOne ":scope span.t-normal:not(t-black--light) > span[aria-hidden=true]" n
  44. light <- queryAndDetachMany ":scope span.t-black--light > span[aria-hidden=true]" n
  45. pure $ ado
  46. b <- bold
  47. in ArtDecoCenterHeader {bold: b, normal: hush normal, light: hush light}
  48. data ArtDecoCenter = ArtDecoCenter {
  49. header :: ArtDecoCenterHeader,
  50. content :: ArtDecoCenterContent
  51. }
  52. derive instance Generic ArtDecoCenter _
  53. instance Show ArtDecoCenter where
  54. show = genericShow
  55. parseArtDecoCenter :: Node -> Effect (Either String ArtDecoCenter)
  56. parseArtDecoCenter n = do
  57. header <- queryOneAndParse ":scope > div" parseArtDecoCenterHeader n
  58. content <- queryOneAndParse ":scope > div ~ div" parseArtDecoCenterContent n
  59. pure $ ado
  60. h <- header
  61. c <- content
  62. in ArtDecoCenter {header: h, content: c}
  63. data ArtDecoPvsEntity = ArtDecoPvsEntity {
  64. side :: Unit,
  65. center :: ArtDecoCenter
  66. }
  67. derive instance Generic ArtDecoPvsEntity _
  68. instance Show ArtDecoPvsEntity where
  69. show = genericShow
  70. parseArtDecoPvsEntity :: Node -> Effect (Either String ArtDecoPvsEntity)
  71. parseArtDecoPvsEntity n = do
  72. center <- queryOneAndParse ":scope > div.display-flex" parseArtDecoCenter n
  73. pure $ ado
  74. c <- center
  75. in ArtDecoPvsEntity {side: unit, center: c}
  76. data ArtDecoCardElement = ArtDecoCardElement {
  77. pvs_entity :: ArtDecoPvsEntity
  78. }
  79. derive instance Generic ArtDecoCardElement _
  80. instance Show ArtDecoCardElement where
  81. show = genericShow
  82. parseArtDecoCard :: Node -> Effect (Either String ArtDecoCardElement)
  83. parseArtDecoCard n = do
  84. pvs <- queryOneAndParse ":scope div.pvs-entity--padded" parseArtDecoPvsEntity n
  85. pure $ ado
  86. p <- pvs
  87. in ArtDecoCardElement {pvs_entity: p}
  88. toParentNode' :: Node -> ParentNode
  89. toParentNode' n =
  90. unsafePartial $ fromJust $ intoParentNode' n where
  91. intoParentNode' :: Node -> Maybe ParentNode
  92. intoParentNode' node = do
  93. he <- E.fromNode node
  94. pure $ E.toParentNode he
  95. queryOne :: String -> Node -> Effect (Maybe Node)
  96. queryOne selector n = do
  97. found <- querySelector (QuerySelector selector) $ toParentNode' n
  98. pure case found of
  99. Nothing -> Nothing
  100. Just el -> Just $ E.toNode el
  101. queryAll :: String -> Node -> Effect (Maybe (NonEmptyList Node))
  102. queryAll selector n = do
  103. found <- querySelectorAll (QuerySelector selector) $ toParentNode' n
  104. liftA1 NEL.fromFoldable $ NL.toArray found
  105. queryAndDetachOne ∷ String -> Node → Effect (Either String DetachedNode)
  106. queryAndDetachOne selector n = do
  107. node <- queryOne selector n
  108. case node of
  109. Nothing -> pure $ Left $ "Could not find node with selector " <> selector
  110. Just node -> do
  111. node <- toDetached node
  112. pure $ Right node
  113. queryAndDetachMany ∷ String -> Node → Effect (Either String (NonEmptyList DetachedNode))
  114. queryAndDetachMany selector n = do
  115. nodes <- queryAll selector n
  116. case nodes of
  117. Nothing -> pure $ Left $ "Did not find any node with selector " <> selector
  118. Just nodes -> do
  119. nodes <- traverse toDetached nodes
  120. pure $ Right nodes
  121. queryOneAndParse ∷ ∀ a. String → (Node → Effect (Either String a)) → Node → Effect (Either String a)
  122. queryOneAndParse selector parser n = do
  123. node <- queryOne selector n
  124. case node of
  125. Nothing -> pure $ Left $ "Could not find node with selector " <> selector
  126. Just node -> parser node