#!/usr/bin/lua local xml2lua = require("xml2lua") -- Just fail early if these dont exist local handler = require("xmlhandler.tree") -- Requires either curl, lua-curl or luasec later -- Uses either notify-send if available or prints new releases to stdout local DEBUG = false local VERSION = 20210229 local RSSURL = "https://hg.mozilla.org/mozilla-unified/rss-tags" local NOTIFY_TITLE = "New Firefox Release" local NOTIFY_TEXT = "Firefox %s was released on %s." local function helpExit(err) if err then print("Error: " .. tostring(err)) end print(([[ Firefox release notifier script version %d ]]):format(VERSION)) os.exit() end local function perhaps(...) local s, l = pcall(require, ...) if s then return l end end local _ = function(s) if type(s) ~= "nil" then return tostring(s) end end local notify local fetch = DEBUG and (function() local f = io.open("rssdump", "r"); local c = f:read("*a"); f:close(); return c end) or nil local which local sh = perhaps("sh") if type(sh) == "table" and type(sh.fork) == "string" and sh.fork == "folknor" and sh.version >= 4 then if not which then which = function(c) return sh._(("which " .. tostring(c))).__exitcode == 0 end end if not notify and which("notify-send") then notify = function(t, m) sh._(("notify-send -i firefox %q %q"):format(t, m)) end end if not fetch and which("curl") then fetch = function(url) return _(sh.command("curl")("-s", url)) end end end if not which then which = function(c) local h = io.popen("which " .. tostring(c)) local r = h:read("*a"); h:close() return #r > 0 end end if not notify then if which("notify-send") then notify = function(t, m) os.execute(("notify-send -i firefox %q %q"):format(t, m)) end else notify = function(t, m) print("[" .. tostring(t) .. "][" .. tostring(m) .. "]") end end end if not fetch then local sec = perhaps("ssl.https") if type(sec) == "table" then fetch = function(url) local res, code = sec.request(url) if code == 200 then return res end end else local curl = perhaps("lcurl") if type(curl) == "table" then fetch = function(url) local raw = "" local easy = curl.easy({ url = url, writefunction = function(inc) raw = raw .. inc return true end }) easy:perform() easy:close() return raw end end end end if not fetch then helpExit("Can't fetch.") end local versionMt = { __eq = function(self, other) return self[1] == other[1] and self[2] == other[2] and self[3] == other[3] end, __lt = function(self, other) if self[1] ~= other[1] then return self[1] < other[1] end if self[2] ~= other[2] then return self[2] < other[2] end return self[3] < other[3] end, __tostring = function(self) return ("%d.%d.%d"):format(unpack(self)) end, } local function parseVersion(...) local v = {...} if select("#", ...) == 1 then v[1], v[2], v[3] = tostring((select(1, ...))):match("^(%d+)%.?(%d*)%.?(%d*)") end v[1], v[2], v[3] = tonumber(v[1]) or 0, tonumber(v[2]) or 0, tonumber(v[3]) or 0 if v[1] == 0 then return false end return setmetatable(v, versionMt) end local lN -- last notified do local f = io.open("notified", "r") lN = parseVersion(f:read("*a")) f:close() end local content = fetch(RSSURL) if type(content) ~= "string" then helpExit("Unable to fetch " .. RSSURL) end local parser = xml2lua.parser(handler) parser:parse(content) for i, ev in next, handler.root.rss.channel.item do if ( ev.title:find("^FIREFOX%_") and ev.title:find("%_RELEASE$") ) then local sv = parseVersion(ev.title:match("^FIREFOX%_(%d+)%_?(%d*)%_?(%d*)%_?RELEASE$")) if sv and sv > lN then notify(NOTIFY_TITLE:format(tostring(sv)), NOTIFY_TEXT:format(tostring(sv), tostring(ev.pubDate))) if not DEBUG then lN = sv local f = io.open("notified", "w+") f:write(tostring(lN)) f:close() end end end end