Something went wrong. Try again.
Something went wrong. Try again.
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116-- Ported from anyfeed-server's overwatch-patch-notes.lua. That version-- rendered a patch's markup to markdown via a shared converter; luafeed-- has no HTML->markdown capability, so `description` here is the patch-- block's plain text instead (loses bold/list formatting, keeps the-- actual words) via `:text()`. Everything else -- title, link, date, and-- crucially no second fetch needed at all, since every patch is already-- inline on this one page -- ports directly.---- site{-- name = "overwatch-patch-notes",-- url = "https://overwatch.blizzard.com/en-us/news/patch-notes/",-- method = "overwatch-patch-notes",-- title = "Overwatch Patch Notes",-- }---- Markup per patch (as of writing):-- <div class="PatchNotes-patch PatchNotes-live">-- <div class="anchor" id="patch-2026-08-20"></div>-- <div class="PatchNotes-labels">-- <div class="PatchNotes-date">August 20, 2026</div>-- </div>-- <h3 class="PatchNotes-patchTitle">Overwatch Retail Patch Notes - August 20, 2026</h3>-- ...section content...-- </div>---- The page only ever renders the current month's patches server-side ---- the year/month selectors re-fetch via client-side JS, which a plain-- fetch doesn't run -- so this only ever sees recent entries. That's the-- right behavior for a feed tracker: older patches were already seen.
local function has_class(node, name) local class = node:attr("class") if not class then return false end for token in class:gmatch("%S+") do if token == name then return true end end return falseend
local function find_by_class(node, tag, class_name) local matches = {} for _, el in ipairs(node:find_all(tag)) do if has_class(el, class_name) then table.insert(matches, el) end end return matchesend
-- Strips any query string/fragment so `#patch-...` can be appended cleanly,-- even if the configured url already carries one.local function page_url_of(url) return url:match("^([^?#]+)")end
-- os.time() interprets a field table as the host's *local* time, and Lua-- has no timezone-aware alternative in the standard library -- this-- converts a UTC field table to the right epoch by computing the host's-- current UTC offset and applying it, rather than assuming the host runs-- in UTC. (Not exact across a DST transition between now and the target-- date, an acceptable approximation for ordering feed items.)local function utc_time(fields) local now = os.time() local isdst = os.date("*t", now).isdst local utc_now = os.date("!*t", now) utc_now.isdst = isdst local offset = now - os.time(utc_now) fields.isdst = isdst return os.time(fields) + offsetend
local function rfc822_midnight(date_part) local year, month, day = date_part:match("^(%d%d%d%d)-(%d%d)-(%d%d)$") if not year then return nil end local timestamp = utc_time({ year = tonumber(year), month = tonumber(month), day = tonumber(day), hour = 0 }) return os.date("!%a, %d %b %Y %H:%M:%S GMT", timestamp)end
local function build_item(page_url, patch) local anchor_el = find_by_class(patch, "div", "anchor")[1] local title_el = find_by_class(patch, "h3", "PatchNotes-patchTitle")[1] if not anchor_el or not title_el then return nil end
local id = anchor_el:attr("id") local date_part = id and id:match("^patch%-(%d%d%d%d%-%d%d%-%d%d)$")
return { title = title_el:text(), link = page_url .. "#" .. id, guid = id, description = patch:text(), pub_date = date_part and rfc822_midnight(date_part), }end
local root, url = ...local page_url = page_url_of(url)local patches = find_by_class(root, "div", "PatchNotes-patch")
local items = {}for _, patch in ipairs(patches) do local item = build_item(page_url, patch) if item then table.insert(items, item) endendreturn items