Something went wrong. Try again.
Something went wrong. Try again.
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130-- Ported from anyfeed-server's eldenring-patch-notes.lua. That version-- fetched each patch's own article page for its full body/description/-- thumbnail; luafeed's method scripts only get the one page Rust already-- fetched, with no way to fetch a second page, so this port only ever sees-- what's on the listing page itself: title, link, and publish date (all-- present directly on the listing card). `description` is left unset-- rather than filled with a listing-page fragment.---- site{-- name = "eldenring-patch-notes",-- url = "https://en.bandainamcoent.eu/elden-ring/elden-ring/news",-- method = "eldenring-patch-notes",-- title = "Elden Ring Patch Notes",-- }---- The page is sectioned by anchored <h2> titles ("Patch Notes (27)"), each-- followed by a <ul class="cards-list">; the patch-notes cards link to-- /elden-ring/news/elden-ring-patch-notes-version-<version> article pages.-- Entries beyond the first handful load via client-side infinite scroll,-- which a plain fetch doesn't run, so only the latest patches are ever-- seen -- the right behavior for a feed tracker, since older patches were-- already recorded by earlier polls. Cards are recognized by their link-- slug rather than their position in a particular section, which survives-- markup reshuffles.
local function origin_of(url) return url:match("^(https?://[^/]+)")end
local function resolve_link(origin, href) if href:match("^https?://") then return href end return origin .. hrefend
-- The stable id: the version tail of the article slug.local function patch_id(href) return href and href:match("patch%-notes%-version%-(.+)$")end
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
-- 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(origin, card, seen) local href = card:attr("href") or "" local id = patch_id(href) -- A duplicate card for the same patch elsewhere on the page (the latest -- patch also appears in the main news list) -- skip it. if not id or seen[id] then return nil end seen[id] = true
local title_el = find_by_class(card, "h3", "card__title")[1] if not title_el then return nil end
local time_el = card:find_all("time")[1] local date_part = time_el and (time_el:attr("datetime") or ""):match("^(%d%d%d%d%-%d%d%-%d%d)")
return { title = title_el:text(), link = resolve_link(origin, href), guid = id, pub_date = date_part and rfc822_midnight(date_part), }end
local root, url = ...local origin = origin_of(url)local lists = find_by_class(root, "ul", "cards-list")local items = {}local seen = {}for _, list in ipairs(lists) do for _, card in ipairs(list:find_all("a")) do local item = build_item(origin, card, seen) if item then table.insert(items, item) end endendreturn items