Módulo:Webarchive

Ourige: Biquipédia, la anciclopédia lhibre.

La decumentaçon pa este módulo puode ser criada na páigina Módulo:Webarchive/doc

--[[ ----------------------------------

     Lua module implementing the {{webarchive}} template.

       A merger of the functionality of three templates: {{wayback}}, {{webcite}} and {{cite archives}}
 
  ]]

local p = {}

--[[--------------------------< inlineError >-----------------------

     Critical error. Render output completely in red. Add to tracking category.

 ]]

local function inlineError(arg, msg)

  track["Catadorie:!Erros na predefeniçon Webarchive"] = 1
  return '<span style="font-size:100%" class="error citation-comment">Erros na predefeniçon Webarchive: Berifique <code style="color:inherit; border:inherit; padding:inherit;">&#124;' .. arg .. '=</code> valor. ' .. msg .. '</span>'

end

--[[--------------------------< inlineRed >-----------------------

      Render a text fragment in red, such as a warning as part of the final output.
      Add tracking category.

 ]]

local function inlineRed(msg, trackmsg)

  if trackmsg == "warning" or trackmsg == "aviso" then
    track["Catadorie:!Erros na predefeniçon Webarchive"] = 1
  elseif trackmsg == "error" or trackmsg == "erro" then
    track["Catadorie:!Erros na predefeniçon Webarchive"] = 1
  end

  return '<span style="font-size:100%" class="error citation-comment">' .. msg .. '</span>'

end

--[[--------------------------< trimArg >-----------------------

     trimArg returns nil if arg is "" while trimArg2 returns 'true' if arg is ""
     trimArg2 is for args that might accept an empty value, as an on/off switch like nolink=

 ]]

local function trimArg(arg)
  if arg == "" or arg == nil then
    return nil
  else
    return mw.text.trim(arg)
  end
end
local function trimArg2(arg)
  if arg == nil then
    return nil
  else
    return mw.text.trim(arg)
  end
end

--[[--------------------------< base62 >-----------------------

     Convert base-62 to base-10
     Credit: https://de.wikipedia.org/wiki/Modul:Expr

  ]]

local function base62( value )

    local r = 1

    if value:match( "^%w+$" ) then
        local n = #value
        local k = 1
        local c
        r = 0
        for i = n, 1, -1 do
            c = value:byte( i, i )
            if c >= 48  and  c <= 57 then
                c = c - 48
            elseif c >= 65  and  c <= 90 then
                c = c - 55
            elseif c >= 97  and  c <= 122 then
                c = c - 61
            else    -- How comes?
                r = 1
                break    -- for i
            end
            r = r + c * k
            k = k * 62
        end -- for i
    end
    return r
end

--[[--------------------------< tableLength >-----------------------

      Given a 1-D table, return number of elements

  ]]

local function tableLength(T)
  local count = 0
  for _ in pairs(T) do count = count + 1 end
  return count
end


--[[--------------------------< dateFormat >-----------------------

     Given a date string, return its format: dmy, mdy, iso, ymd
       If unable to determine return nil

  ]]

local function dateFormat(date)

  local dt = {}
  dt.split = {}

  dt.split = mw.text.split(date, "-")
  if tableLength(dt.split) == 3 then
    if tonumber(dt.split[1]) > 1900 and tonumber(dt.split[1]) < 2200 and tonumber(dt.split[2]) and tonumber(dt.split[3]) then
      return "iso"
    else
      return nil
    end
  end

  dt.split = mw.text.split(date, " ")
  if tableLength(dt.split) == 3 then
    if tonumber(dt.split[3]) then
      if tonumber(dt.split[3]) > 1900 and tonumber(dt.split[3]) < 2200 then
        if tonumber(dt.split[1]) then
          return "dmy"
        else
          return "mdy"
        end
      else
        if tonumber(dt.split[1]) then
          if tonumber(dt.split[1]) > 1900 and tonumber(dt.split[1]) < 2200 then
            return "ymd"
          end
        end
      end
    end
  end
  return nil

end

--[[--------------------------< makeDate >-----------------------

     Given a zero-padded 4-digit year, 2-digit month and 2-digit day, return a full date in df format
     df = mdy, dmy, iso, ymd

 ]]

local function makeDate(year, month, day, df)
  local month_names = {"janeiro", "febreiro", "márcio", "abril", "maio", "júnio", "júlio", "agosto", "setembre", "outubre", "nobembre", "dezembre"}

  if not year or year == "" or not month or month == "" or not day or day == "" then
    return nil
  end

  local zmonth = month                                                      -- month with leading 0
  month = month:match("0*(%d+)")                                            -- month without leading 0
  if tonumber(month) < 1 or tonumber(month) > 12 then
    return year
  end
  local nmonth = month_names[tonumber(month)]
--  local nmonth = os.date("%B", os.time{year=2000, month=month, day=1} )     -- month in name form    
  if not nmonth then
    return year
  end

  local zday = day
  day = zday:match("0*(%d+)")
  if tonumber(day) < 1 or tonumber(day) > 31 then
    if df == "mdy" or df == "dmy" then
      return nmonth .. " " .. year
    elseif df == "iso" then
      return year .. "-" .. zmonth
    elseif df == "ymd" then
      return year .. " " .. nmonth
    else
      return nmonth .. " " .. year
    end
  end                                    

  if df == "mdy" then
    return nmonth .. " " .. day .. ", " .. year         -- setembre 1, 2016
  elseif df == "dmy" then
    return day .. " de " .. nmonth .. " de  " .. year          -- 1 de setembre de 2016
  elseif df == "iso" then
    return year .. "-" .. zmonth .. "-" .. zday         -- 2016-09-01
  elseif df == "ymd" then
    return year .. " " .. nmonth .. " " .. cday          -- 2016 setembre 1
  else
    return day .. " de " .. nmonth .. " de " .. year         -- 1 de setembre de 2016
  end

end


--[[--------------------------< decodeWebciteDate >-----------------------

      Given a URI-path to Webcite (eg. /67xHmVFWP) return the encoded date in df format

  ]]
local function decodeWebciteDate(path, df)

    local dt = {}
    dt.split = {}

    dt.split = mw.text.split(path, "/")

    -- valid URL formats that are not base62
    --  http://www.webcitation.org/query?id=1138911916587475
    --  http://www.webcitation.org/1138911916587475
    --  http://www.webcitation.org/cache/73e53dd1f16cf8c5da298418d2a6e452870cf50e
    if dt.split[2] == "query" or dt.split[2] == "cache" or tonumber(dt.split[2]) then
      return "query"
    end

    dt.full = os.date("%Y %m %d", string.sub(string.format("%d", base62(dt.split[2])),1,10) )
    dt.split = mw.text.split(dt.full, " ")
    dt.year = dt.split[1]
    dt.month = dt.split[2]
    dt.day = dt.split[3]

    if not tonumber(dt.year) or not tonumber(dt.month) or not tonumber(dt.day) then
      return inlineRed("[Erro data] (1)", "erro")
    end

    if tonumber(dt.month) > 12 or tonumber(dt.day) > 31 or tonumber(dt.month) < 1 then
      return inlineRed("[Erro data] (2)", "erro")
    end
    if tonumber(dt.year) > tonumber(os.date("%Y")) or tonumber(dt.year) < 1900 then
      return inlineRed("[Erro data] (3)", "erro")
    end

    fulldate = makeDate(dt.year, dt.month, dt.day, df)
    if not fulldate then
      return inlineRed("[Erro data] (4)", "erro")
    else
      return fulldate
    end

end

--[[--------------------------< snapDateToString >-----------------------

Given a URI-path to Wayback (eg. /web/20160901010101/http://example.com )
  return the formatted date eg. "September 1, 2016" in df format
  Handle non-digits in snapshot ID such as "re_" and "-" and "*"

 ]]

local function decodeWaybackDate(path, df)

    local snapdate, snapdatelong, currdate, fulldate

    local safe = path
    snapdate = string.gsub(safe, "^/w?e?b?/?", "")                      -- Remove leading "/web/" or "/"
    safe = snapdate
    local N = mw.text.split(safe, "/")
    snapdate = N[1]
    if snapdate == "*" then                                             -- eg. /web/*/http..
      return "index"
    end
    safe = snapdate
    snapdate = string.gsub(safe, "[a-z][a-z]_[0-9]?$", "")              -- Remove any trailing "re_" from date
    safe = snapdate
    snapdate = string.gsub(safe, "[-]", "")                             -- Remove dashes from date eg. 2015-01-01
    safe = snapdate
    snapdate = string.gsub(safe, "[*]$", "")                            -- Remove trailing "*"

    if not tonumber(snapdate) then
      return inlineRed("[Erro data] (2)", "erro")
    end
    local dlen = string.len(snapdate)
    if dlen < 4 then
      return inlineRed("[Erro data] (3)", "erro")
    end
    if dlen < 14 then
      snapdatelong = snapdate .. string.rep("0", 14 - dlen)
    else
      snapdatelong = snapdate
    end
    local year = string.sub(snapdatelong, 1, 4)
    local month = string.sub(snapdatelong, 5, 6)
    local day = string.sub(snapdatelong, 7, 8)
    if not tonumber(year) or not tonumber(month) or not tonumber(day) then
      return inlineRed("[Erro data] (4)", "erro")
    end
    if tonumber(month) > 12 or tonumber(day) > 31 or tonumber(month) < 1 then
      return inlineRed("[Erro data] (5)", "erro")
    end
    currdate = os.date("%Y")
    if tonumber(year) > tonumber(currdate) or tonumber(year) < 1900 then
      return inlineRed("[Erro data] (6)", "erro")
    end

    fulldate = makeDate(year, month, day, df)
    if not fulldate then
      return inlineRed("[Erro data] (7)", "erro")
    else
      return fulldate
    end

end


--[[--------------------------< serviceName >-----------------------

     Given a domain extracted by mw.uri.new() (eg. web.archive.org) set tail string and service ID

  ]]

local function serviceName(host, nolink)

  local tracking = "Catadorie:!Predefeniçon Webarchive outros arquibos"

  local bracketopen = "[["
  local bracketclose = "]]"
  if nolink then
    bracketopen = ""
    bracketclose = ""
  end

  ulx.url1.service = "outro"
  ulx.url1.tail = " ne l " .. ulx.url1.host

  if mw.ustring.find( host, "archive.org", 1, plain ) then
    ulx.url1.service = "wayback"
    ulx.url1.tail = " ne l " .. bracketopen .. "Wayback Machine" .. bracketclose
    tracking = "Catadorie:!Predefeniçon Webarchive wayback links"
  elseif mw.ustring.find( host, "webcitation.org", 1, plain ) then
    ulx.url1.service = "webcite"
    ulx.url1.tail = " ne l " .. bracketopen .. "WebCite" .. bracketclose
    tracking = "Catadorie:!Predefeniçon Webarchive webcite links"
  elseif mw.ustring.find( host, "archive.is", 1, plain ) then
    ulx.url1.service = "archiveis"
    ulx.url1.tail = " ne l " .. bracketopen .. "Archive.is" .. bracketclose
    tracking = "Catadorie:!Predefeniçon Webarchive archiveis links"
  elseif mw.ustring.find( host, "archive.today", 1, plain ) then
    ulx.url1.service = "archiveis"
    ulx.url1.tail = " ne l " .. bracketopen .. "Archive.is" .. bracketclose
    tracking = "Catadorie:!Predefeniçon Webarchive archiveis links"
  elseif mw.ustring.find( host, "archive-it", 1, plain ) then
    ulx.url1.service = "archiveit"
    ulx.url1.tail = " ne l " .. bracketopen .. "Archive-It" .. bracketclose
  elseif mw.ustring.find( host, "arquibo.pt", 1, plain) then
    ulx.url1.tail = " ne l " .. "Arquibo Web Mirandés"
  elseif mw.ustring.find( host, "loc.gov", 1, plain ) then
    ulx.url1.tail = " na " .. bracketopen .. "Biblioteca de l Cungresso" .. bracketclose
  elseif mw.ustring.find( host, "webharvest.gov", 1, plain ) then
    ulx.url1.tail = " ne ls " .. bracketopen .. "Arquibos Nacionales i Admenistraçon de Decumientos de ls Stados Ounidos" .. bracketclose
  elseif mw.ustring.find( host, "bibalex.org", 1, plain ) then
    ulx.url1.tail = " na " .. "[[Bibliotheca_Alexandrina]]"
  elseif mw.ustring.find( host, "collectionscanada", 1, plain ) then
    ulx.url1.tail = " ne l " .. "Arquibo Web de l Gobierno Canadiano"
  elseif mw.ustring.find( host, "haw.nsk", 1, plain ) then
    ulx.url1.tail = " ne l " .. "Arquibo Web Croata (HAW)"
  elseif mw.ustring.find( host, "nlib.ee", 1, plain ) then
    ulx.url1.tail = " ne l " .. "Arquibo web Stoniano"
  elseif mw.ustring.find( host, "vefsafn.is", 1, plain ) then
    ulx.url1.tail = " ne l " .. "Arquibo Web Eislandés"
  elseif mw.ustring.find( host, "proni.gov", 1, plain ) then
    ulx.url1.tail = " ne l " .. bracketopen .. "Cunserbatória de Registos Públicos de la Irlanda de l Norte" .. bracketclose
  elseif mw.ustring.find( host, "uni-lj.si", 1, plain ) then
    ulx.url1.tail = " ne l " .. "Arquibo Web Slobeno"
  elseif mw.ustring.find( host, "stanford.edu", 1, plain ) then
    ulx.url1.tail = " nas " .. "Bibliotecas de la Ounibersidade de Stanford"
  elseif mw.ustring.find( host, "nationalarchives.gov.uk", 1, plain ) then
    ulx.url1.tail = " ne l " .. bracketopen .. "Arquibo Web de l Gobierno de l Reino Ounido" .. bracketclose
  elseif mw.ustring.find( host, "parliament.uk", 1, plain ) then
    ulx.url1.tail = " ne l " .. bracketopen .. "Arquibo Web de l Parlamiento de l Reino Ounido" .. bracketclose
  elseif mw.ustring.find( host, "webarchive.org.uk", 1, plain ) then
    ulx.url1.tail = " ne l " .. bracketopen .. "Arquibo Web de l Reino Ounido" .. bracketclose
  elseif mw.ustring.find( host, "nlb.gov.sg", 1, plain ) then
    ulx.url1.tail = " ne l " .. "Arquibo Web de la Singapura"
  elseif mw.ustring.find( host, "screenshots.com", 1, plain ) then
    ulx.url1.tail = " ne l " .. "Screenshots"
  elseif mw.ustring.find( host, "wikiwix.com", 1, plain ) then
    ulx.url1.tail = " ne l " .. "Wikiwix"
  elseif mw.ustring.find( host, "perma.cc", 1, plain ) then
    ulx.url1.tail = " ne l " .. bracketopen .. "Perma.cc" .. bracketclose
  else
    tracking = "Catadorie:!Predefeniçones Webarchive arquibos çconhecidos"
  end

  track[tracking] = 1

end

--[[--------------------------< parseExtraArgs >-----------------------

     Parse numbered arguments starting at 2, such as url2..url10, date2..date10, title2..title10
       For example: {{webarchive |url=.. |url4=.. |url7=..}}
         Three url arguments not in numeric sequence (1..4..7).
         Function only processes arguments numbered 2 or greater (in this case 4 and 7)
         It creates numeric sequenced table entries like:
           urlx.url2.url = <argument value for url4>
           urlx.url3.url = <argument value for url7>
       Returns the number of URL arguments found numbered 2 or greater (in this case returns "2")

 ]]

local function parseExtraArgs()

  local i, j, argurl, argurl2, argdate, argtitle

  j = 2
  for i = 2, maxurls do
    argurl = "url" .. i
    if trimArg(args[argurl]) then
      argurl2 = "url" .. j
      ulx[argurl2] = {}
      ulx[argurl2]["url"] = args[argurl]
      argdate = "data" .. j
      if trimArg(args[argdate]) then
        ulx[argurl2]["date"] = args[argdate]
      else
        ulx[argurl2]["date"] = inlineRed("[Falta data]", "aviso")
      end
      argtitle = "título" .. j
      if trimArg(args[argtitle]) then
        ulx[argurl2]["title"] = args[argtitle]
      else
        ulx[argurl2]["title"] = nil
      end
      j = j + 1
    end
  end

  if j == 2 then
    return 0
  else
    return j - 2
  end

end

--[[--------------------------< comma >-----------------------

     Given a date string, return "," if it's MDY

  ]]

local function comma(date)
  local N = mw.text.split(date, " ")
  local O = mw.text.split(N[1], "-") -- for ISO
  if O[1] == "index" then return "" end
  if not tonumber(O[1]) then
    return ","
  else
    return ""
  end
end

--[[--------------------------< createTracking >-----------------------

     Return data in track[] ie. tracking categories

  ]]

local function createTracking()

  local sand = ""
  if tableLength(track) > 0 then                     
    for key,_ in pairs(track) do
      sand = sand .. "[[" .. key .. "]]"
    end
  end
  return sand

end

--[[--------------------------< createRendering >-----------------------

     Return a rendering of the data in ulx[][]

  ]]

local function createRendering()

    local sand, displayheader, displayfield

    local period1 = ""   -- For backwards compat with {{wayback}}
    local period2 = "."                                                         
 
    local indexstr = "arquibado"
    if ulx.url1.date == "index" then
      indexstr = "arquibo"
    end
                                                                                          -- For {{wayback}}, {{webcite}}

    if ulx.url1.format == "none" then                                                  
      if not ulx.url1.title and not ulx.url1.date then                                    -- No title. No date
        sand = "[" .. ulx.url1.url .. " Cópia de l'arquibo]" .. ulx.url1.tail
      elseif not ulx.url1.title and ulx.url1.date then                                    -- No title. Date.
        if ulx.url1.service == "wayback" then
          period1 = "."
          period2 = ""
        end
        sand = "[" .. ulx.url1.url .. " Arquibado an] " .. ulx.url1.date .. comma(ulx.url1.date) .. ulx.url1.tail .. period1
      elseif ulx.url1.title and not ulx.url1.date then                                    -- Title. No date.
        sand = "[" .. ulx.url1.url .. " " .. ulx.url1.title .. "]" .. ulx.url1.tail
      elseif ulx.url1.title and ulx.url1.date then                                        -- Title. Date.
        sand = "[" .. ulx.url1.url .. " " .. ulx.url1.title .. "]" .. ulx.url1.tail .. "&#32;(" .. indexstr .. " " .. ulx.url1.date .. ")"
      else
        return nil
      end
      if ulx.url1.extraurls > 0 then                                                      -- For multiple archive URLs
        local tot = ulx.url1.extraurls + 1
        sand = sand .. period2 .. " Arquibos adicionales: "
        for i=2,tot do
          local indx = "url" .. i
          if ulx[indx]["title"] then
            displayfield = "title"
          else
            displayfield = "date"
          end
          sand = sand .. "[" .. ulx[indx]["url"] .. " " .. ulx[indx][displayfield] .. "]"
          if i == tot then
            sand = sand .. "."
          else
            sand = sand .. ", "
          end
        end
      else
        return sand
      end
      return sand
                                                                                          -- For {{cite archives}}

    else                                                               
      if ulx.url1.format == "addlarchives" then                           -- Multiple archive services
        displayheader = "Arquibos adicionales: "
      else                                                                -- Multiple pages from the same archive
        displayheader = "Páginas arquivadas&nbsp;em " .. ulx.url1.date .. ": "
      end
      local tot = 1 + ulx.url1.extraurls
      local sand = displayheader
      for i=1,tot do
        local indx = "url" .. i
        displayfield = ulx[indx]["title"]
        if ulx.url1.format == "addlarchives" then
          if not displayfield then
            displayfield = ulx[indx]["date"]
          end
        else
          if not displayfield then
            displayfield = "Página " .. i
          end
        end
        sand = sand .. "[" .. ulx[indx]["url"] .. " " .. displayfield .. "]"
        if i == tot then
          sand = sand .. "."
        else
          sand = sand .. ", "
        end
      end
      return sand
    end
end

function p.webarchive(frame)
  args = frame.args
  if (args[1]==nil) and (args["url"]==nil) then           -- if no argument provided than check parent template/module args
    args = frame:getParent().args
  end
 
  local tname = "Webarchive"                              -- name of calling template. Change if template rename.
  ulx = {}                                                -- Associative array to hold template data
  track = {}                                              -- Associative array to hold tracking categories
  maxurls = 10                                            -- Max number of URLs allowed.
  local verifydates = "yes"                               -- See documentation. Set "no" to disable.

                                                          -- URL argument (first)

  local url1 = trimArg(args.url) or trimArg(args.url1)        
  if not url1 then
    return inlineError("url", "Vazio.") .. createTracking()
  end
  if mw.ustring.find( url1, "https://web.http", 1, plain ) then    -- track bug
    track["Catadorie:!Erros na predefeniçon Webarchive"] = 1
    return inlineError("url", "https://web.http") .. createTracking()
  end

  ulx.url1 = {}
  ulx.url1.url = url1
  local uri1 = mw.uri.new(ulx.url1.url)
  ulx.url1.host = uri1.host
  ulx.url1.extraurls = parseExtraArgs()

                                                          -- Nolink argument

  local nolink = trimArg2(args.nolink)

  serviceName(uri1.host, nolink)

                                                          -- Date argument

  local date = trimArg(args.date) or trimArg(args.date1)
  if date == "*" and ulx.url1.service == "wayback" then
    date = "index"
  elseif date and ulx.url1.service == "wayback" and verifydates == "yes" then
    local ldf = dateFormat(date)
    if ldf then
      local udate = decodeWaybackDate( uri1.path, ldf )
      if udate ~= date then
        date = udate .. inlineRed("<sup>[Erro data trocada]</sup>", "aviso")    
      end
    end
  elseif date and ulx.url1.service == "webcite" and verifydates == "yes" then
    local ldf = dateFormat(date)
    if ldf then
      local udate = decodeWebciteDate( uri1.path, ldf )
      if udate == "query" then -- skip
      elseif udate ~= date then
        date = udate .. inlineRed("<sup>[Erro data trocada]</sup>", "aviso")   
      end
    end
  elseif not date and ulx.url1.service == "wayback" then
    date = decodeWaybackDate( uri1.path, "iso" )
    if not date then
      date = inlineRed("[Erro data] (1)", "erro")
    end
  elseif not date and ulx.url1.service == "webcite" then
    date = decodeWebciteDate( uri1.path, "iso" )
    if date == "query" then
      date = inlineRed("[Falta a data]", "aviso")
    elseif not date then
      date = inlineRed("[Erro data] (1)", "erro")
    end
  elseif not date then
    date = inlineRed("[Falta la data]", "abiso")
  end
  ulx.url1.date = date

                                                          -- Format argument

  local format = trimArg(args.format)
  if not format then
    format = "none"
  else
    if format == "addlpages" then
      if not ulx.url1.date then
        format = "none"
      end
    elseif format == "addlarchives" then
      format = "addlarchives"
    else
      format = "none"
    end
  end
  ulx.url1.format = format

                                                          -- Title argument

  local title = trimArg(args.title) or trimArg(args.title1)
  ulx.url1.title = title
 

  local rend = createRendering()
  if not rend then
    rend = '<span style="font-size:100%" class="error citation-comment">Erro na [[:Predefeniçon:' .. tname .. ']]: Porblema çconhecido. Por fabor relate na páigina de çcusson desta predefeniçon.</span>'
    track["Catadorie:!Predefeniçones cun erros Webarchive"] = 1
  end

  return rend .. createTracking()

end

return p