summaryrefslogtreecommitdiff
path: root/src/weepinbell/metadata/html_head.clj
blob: 9a020df12de0bbc2ec9de47d64336a6a30eca2ae (plain)
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
 (ns weepinbell.metadata.html-head
   "HTML <head> parser that takes a hickory document, then tries 
    to gather information from basic <meta> properties, Open Graph
    protocol, Twitter <meta> tags and <link> with rel attribute,
    and finally compiles to a JF2 object.
    
    This namespace also contains some utility functions to manipulate
    a hickory document."
   (:require [weepinbell.metadata.jf2-spec]))

(defn get-child
  "Get a specific type of tag inside a hickory object."
  [tag hickory]
  (->> hickory :content (filter #(= (:tag %) tag)) first))

(defn get-meta
  "Gets <meta> tags from a hickory document. Returns a seq of maps.
   e.g. ({:name \"description\", :content \"A sentence.\"})"
  [hickory]
  (->> hickory :content
       (filter #(= (:tag %) :meta))
       (map #(get-in % [:attrs]))
       (filter #(and (or (:name %) (:property %))
                     (:content %)))))
(defn get-rels
  "Gets <link> tags with rel attribute from a hickory document.
   Returns a seq of maps, e.g. ({:rel ..., :href ...})"
  [hickory]
  (->> hickory :content
       (filter #(= (:tag %) :link))
       (map #(get-in % [:attrs]))
       (filter #(and (:rel %)
                     (:href %)))))
(defn attrs->map
  "Converts a seq of maps to a regular map, like this:
   ({:name \"a\", :content \"a\"} {:property \"b\", :content \"b\"})
   becomes {\"a\" \"a\", \"b\" \"b\"}"
  [meta-attrs]
  (let [{:keys [property name content rel href]} meta-attrs]
    {(or name property rel) (or content href)}))

(defn get-metadata
  "Takes a hickory data object, returns a map of <meta> name/content"
  [hickory]
  (->> hickory (get-child :html) (get-child :head)
       get-meta (map attrs->map) (reduce merge)))

(defn get-title
  "Takes a hickory data object, returns content of <title>."
  [hickory]
  (->> hickory (get-child :html) (get-child :head)
       :content (filter #(= (:tag %) :title)) first
       :content first))

(defn get-reldata
  "Takes a hickory data object, returns a map of <link> rel/hrefs"
  [hickory]
  (->> hickory (get-child :html) (get-child :head)
       get-rels (map attrs->map) (reduce merge)))

(defn parse-meta
  "Takes hickory document, parses <meta> <link> <title> tags, 
   returns a jf2 map. Supports Open Graph protocol and more."
  [hickory]
  (let [data (get-metadata hickory)
        rels (get-reldata hickory)]
    {:type "entry"
     :name (or (get data "og:title")
               (get data "twitter:title")
               (get-title hickory))
     :url (or (get data "og:url")
              (get data "twitter:url")
              (get rels "canonical"))
     :author {:type "card"
              :name (or (get data "article:author")
                        (get data "twitter:creator")
                        (get data "profile:username")
                        (let [fullname
                              (str (get data "profile:first_name")
                                   " " (get data "profile:last_name"))]
                          (when (not= fullname " ") fullname)))
              :url nil
              :photo (get rels "icon")}
     :published (get data "article:published_time")
     :content ""
     :wm-property :mention
     :summary (or (get data "og:description")
                  (get data "description")
                  (get data "twitter:description"))}))