Просмотр исходного кода

Add thumbnails; pairtrees everywhere.

scossu 1 неделя назад
Родитель
Сommit
90fe029803
4 измененных файлов с 96 добавлено и 36 удалено
  1. 1 1
      README.md
  2. 36 0
      src/core.lua
  3. 51 30
      src/html_generator.lua
  4. 8 5
      templates/index.html

+ 1 - 1
README.md

@@ -161,7 +161,7 @@ Simple road map for a rough prototype:
   - ✓ Index
   - ✓ Resource
   - ✓ Static assets
-  -  Transformers
+  -  Transformers
 - ⎊ Non-HTML generators
   - LL
   - RDF (turtle)

+ 36 - 0
src/core.lua

@@ -1,3 +1,4 @@
+local dir = require "pl.dir"
 local path = require "pl.path"
 local store = require "volksdata.store"
 
@@ -43,4 +44,39 @@ M.RDF_TYPE = term.new_iriref_ns("rdf:type", M.nsm)
 -- Initialize random ID generator.
 math.randomseed(M.config.id.seed[1], M.config.id.seed[2])
 
+
+local par_ns = namespace.get_ns("par")
+
+--[[
+  Gnerate pairtree directory and file path from an ID string and prefix.
+
+  The directory is created if not existing.
+
+  The ID string can include the `par:` namespace prefix or the fully qualified
+  namespace.
+
+  ext is optional, and is appended to the raw path.
+
+  if no_create is not nil or false, the directory will not be checked for
+  existence or created.
+
+  return: full file path, with the optional extension if provided.
+--]]
+M.gen_pairtree = function (pfx, id_str, ext, no_create)
+    local bare_id = id_str:gsub(par_ns, ""):gsub("^par:", "")
+    local res_dir = path.join(pfx, bare_id:sub(1,2), bare_id:sub(3,4))
+
+    local created, err
+    if (path.isdir(res_dir)) or no_create then created = false
+    else
+        created, err = dir.makepath(res_dir)
+        if not created then error(err) end
+    end
+
+    local fpath
+    if (res_dir) then fpath = path.join(res_dir, bare_id .. (ext or "")) end
+
+    return fpath, created
+end
+
 return M

+ 51 - 30
src/html_generator.lua

@@ -22,6 +22,7 @@ local gr = graph.new(pkar.store, term.DEFAULT_CTX)
 
 -- Some commonly used terms.
 local dc_title_p = term.new_iriref_ns("dc:title")
+local dc_created_p = term.new_iriref_ns("dc:created")
 local tn_p = term.new_iriref_ns("pas:thumbnail")
 local first_p = term.new_iriref_ns("pas:first")
 local next_p = term.new_iriref_ns("pas:next")
@@ -77,7 +78,7 @@ end
 
 
 local function get_tn_url(s)
-    if gr:attr(s, pkar.RDF_TYPE)[file_t] then
+    if gr:attr(s, pkar.RDF_TYPE)[file_t.hash] then
         -- The subject is a file.
         tn_fname = (s.data:gsub(par_ns, "") .. ".jpg")  -- FIXME do not hardcode.
         return plpath.join(
@@ -86,7 +87,8 @@ local function get_tn_url(s)
 
     -- Recurse through all first children until one with a thumbnail, or a
     -- leaf without children, is found.
-    first_child = next(gr:attr(s, first_p))
+    local first_child
+    _, first_child = next(gr:attr(s, first_p))
     if first_child then return get_tn_url(first_child) end
 end
 
@@ -106,36 +108,37 @@ local function generate_dres(s, mconf)
         elseif ((mconf.properties or NT)[fname] or NT).type == "rel" then
             -- Relationship.
             rel[fname] = {label = p_label, uri = fname}
-            for o in pairs(ots) do table.insert(dmd[fname], o.data) end
+            for _, o in pairs(ots) do table.insert(dmd[fname], o.data) end
         elseif fname == "pas:first" then
             -- Build a linked list for every first found.
-            for o in pairs(ots) do
+            for _, o in pairs(ots) do
                 -- Loop through all first children.
                 local child_s = o
                 logger:debug("local child_s: ", child_s.data)
                 local ll = {}
-                require "debugger"()
+                local label
+                _, label = next(gr:attr(child_s, dc_title_p))
                 while child_s do
                     -- Loop trough all next nodes for each first child.
                     table.insert(ll, {
-                        href = child_s.data:gsub(
-                                nsm.get_ns("par"), "/res/") .. ".html",
-                        label = (next(gr:attr(child_s, dc_title_p)) or NT).data,
-                        tn = get_tn_url(child_s),
+                        href = pkar.gen_pairtree(
+                                "/res", child_s.data, ".html", true),
+                        label = (label or NT).data,
+                        tn = get_tn_url(child_s):gsub(M.media_dir, "/media/tn"),
                     })
                     -- There can only be one "next"
-                    child_s = next(gr:attr(child_s, next_p))
+                    _, child_s = next(gr:attr(child_s, next_p))
                 end
                 table.insert(children, ll)
             end
         elseif fname == "pas:next" then
             -- Sibling.
-            for o in pairs(ots) do ls_next = o.data break end
+            for _, o in pairs(ots) do ls_next = o.data break end
         else
             -- Descriptive metadata.
             local attr = {label = p_label, uri = fname}
             -- TODO differentiate term types
-            for o in pairs(ots) do table.insert(attr, o.data) end
+            for _, o in pairs(ots) do table.insert(attr, o.data) end
             table.sort(attr)
             if p == dc_title_p then title = attr[1] end
             table.insert(dmd, attr)
@@ -164,9 +167,8 @@ local function generate_dres(s, mconf)
         breadcrumbs = get_breadcrumbs(mconf),
     })
 
-    local res_id = s.data:gsub(nsm.get_ns("par"), "")
-    local ofh = assert(io.open(string.format(
-            "%s/%s.html", M.res_dir, res_id), "w"))
+    local res_path = pkar.gen_pairtree(M.res_dir, s.data, ".html")
+    local ofh = assert(io.open(res_path, "w"))
     ofh:write(out_html)
     ofh:close()
 
@@ -187,15 +189,15 @@ local function generate_ores(s, mconf)
         elseif ((mconf.properties or NT)[fname] or NT).type == "rel" then
             -- Relationship.
             rel[fname] = {label = p_label, uri = fname}
-            for o in pairs(ots) do table.insert(techmd[fname], o.data) end
+            for _, o in pairs(ots) do table.insert(techmd[fname], o.data) end
         elseif fname == "pas:next" then
             -- Sibling.
-            for o in pairs(ots) do ls_next = o.data break end
+            for _, o in pairs(ots) do ls_next = o.data break end
         else
             -- Descriptive metadata.
             techmd[fname] = {label = p_label, uri = fname}
             -- TODO differentiate term types
-            for o in pairs(ots) do table.insert(techmd[fname], o.data) end
+            for _, o in pairs(ots) do table.insert(techmd[fname], o.data) end
             table.sort(techmd[fname])
         end
         ::skip::
@@ -239,7 +241,7 @@ local function generate_ores(s, mconf)
         dest = plpath.join(dest_dir, dest_fname)
         assert(transformers[txconf.fn](
                 res_path[1], dest, table.unpack(txconf or NT)))
-        tn = dest:gsub(pkar.config.htmlgen.out_dir, "")
+        tn = dest:gsub(M.media_dir, "/media/tn")
         logger:info("Thumbnail: ", tn)
     end
 
@@ -257,9 +259,8 @@ local function generate_ores(s, mconf)
         thumbnail = tn,
     })
 
-    local res_id = s.data:gsub(nsm.get_ns("par"), "")
-    local ofh = assert(io.open(string.format(
-            "%s/%s.html", M.res_dir, res_id), "w"))
+    local res_path = pkar.gen_pairtree(M.res_dir, s.data, ".html")
+    local ofh = assert(io.open(res_path, "w"))
     ofh:write(out_html)
     ofh:close()
 
@@ -268,9 +269,20 @@ end
 
 
 M.generate_resource = function(s)
-    local res_type = next(gr:attr(s, content_type_p)).data
-    local mconf = model.models[res_type]
+    local res_type
+    _, res_type = next(gr:attr(s, content_type_p))
+    local mconf = model.models[res_type.data]
+
+    -- Generate RDF/Turtle doc.
+    local res_gr = graph.new(nil, s.data)
+    gr:copy(res_gr, s)
+    logger:debug("Serializing graph: ", s.data)
+    local res_path = pkar.gen_pairtree(M.res_dir, s.data, ".ttl")
+    local ofh = assert(io.open(res_path, "w"))
+    ofh:write(res_gr:encode("nt"))
+    ofh:close()
 
+    -- Generate HTML doc.
     if mconf.types["pas:File"] then return generate_ores(s, mconf)
     else return generate_dres(s, mconf) end
 end
@@ -280,7 +292,7 @@ M.generate_resources = function()
     local subjects = gr:unique_terms(triple.POS_S)
 
     -- TODO parallelize
-    for s in pairs(subjects) do assert(M.generate_resource(s)) end
+    for _, s in pairs(subjects) do assert(M.generate_resource(s)) end
 
     return true
 end
@@ -293,11 +305,20 @@ M.generate_idx = function()
         pkar.RDF_TYPE, triple.POS_P,
         term.new_iriref_ns("pas:Artifact"), triple.POS_O
     )
-    for s in pairs(s_ts) do
-        local s_label = nsm.denormalize_uri(s.data)
-        local obj = {title = next(gr:attr(s, dc_title_p))}
-        if obj.title then obj_idx[s_label] = obj end
+    for _, s in pairs(s_ts) do
+        local title, created
+        _, title = next(gr:attr(s, dc_title_p))
+        _, created = next(gr:attr(s, dc_created_p))
+
+        local obj = {
+            href = pkar.gen_pairtree("/res", s.data, ".html", true),
+            title = title,
+            created = created.data,
+            tn = get_tn_url(s):gsub(M.media_dir, "/media/tn"),
+        }
+        table.insert(obj_idx, obj)
     end
+    table.sort(obj_idx, function(a, b) return a.created < b.created end)
 
     logger:debug(pp.write(obj_idx))
     out_html = idx_tpl({
@@ -326,8 +347,8 @@ M.generate_site = function()
     dir.rmtree(M.media_dir)
     dir.makepath(plpath.join(M.media_dir, "tn"))
 
-    assert(M.generate_idx())
     assert(M.generate_resources())
+    assert(M.generate_idx())
     dir.clonetree("templates/assets", plpath.dirname(M.asset_dir), dir.copyfile)
 end
 

+ 8 - 5
templates/index.html

@@ -11,12 +11,15 @@
             <section id="obj_list">
                 <h2>Recent artifacts</h2>
                 <ul>
-                <% for uri, data in pairs(obj_idx) do %>
+                <% for _, obj in ipairs(obj_idx) do %>
                     <li class="obj_link">
-                        <a href="<%= uri:gsub('par:', '/res/') %>.html">
-                            <%= data.title.data %>
-                            <%if data.title.lang then %>
-                                <span class="langtag"><%= data.title.lang %></span>
+                        <a href="<%= obj.href %>">
+                            <%if obj.tn then %>
+                                <img src="<%= obj.tn %>" alt="<%= obj.title.data %>" />
+                            <% end %>
+                            <%= obj.title.data %>
+                            <%if obj.title.lang then %>
+                                <span class="langtag"><%= obj.title.lang %></span>
                             <% end %>
                         </a>
                     </li>