diff --git a/lib/util.js b/lib/util.js index 7b4c67f..a78f49d 100644 --- a/lib/util.js +++ b/lib/util.js @@ -51,31 +51,48 @@ exports.elapsed = async (fn) => { * / * // */ -exports.parseUsage = (dayDate, rows) => - rows - .map(([uri, byteStr]) => { - const parts = uri.split("/"); - const bytes = parseInt(byteStr, 10); - const day = dayDate.toISOString().split("T").shift(); +exports.parseUsage = (dayDate, rows) => { + const day = dayDate.toISOString().split("T").shift(); + const usage = []; + const unknowns = {}; - if (parts[0].match(/^[0-9]+$/)) { - /* eslint-disable camelcase */ - const feeder_podcast = parseInt(parts[0], 10); - const feeder_feed = parts[1]; - const feeder_episode = parts[parts.length - 1]; - if (parts.length === 2) { - return { feeder_podcast, feeder_episode, bytes, day }; - } - if (parts.length === 3) { - return { feeder_podcast, feeder_feed, feeder_episode, bytes, day }; - } - /* eslint-enable camelcase */ - } + // parse paths + for (const row of rows) { + const uri = row[0]; + const parts = uri.split("/"); + const bytes = parseInt(row[1], 10); + if (parts[0].match(/^[0-9]+$/)) { + /* eslint-disable camelcase */ + const feeder_podcast = parseInt(parts[0], 10); + const feeder_feed = parts[1]; + const feeder_episode = parts[parts.length - 1]; + if (parts.length === 2) { + usage.push({ feeder_podcast, feeder_episode, bytes, day }); + } else if (parts.length === 3) { + usage.push({ feeder_podcast, feeder_feed, feeder_episode, bytes, day }); + } else { + unknowns[feeder_podcast] = (unknowns[feeder_podcast] || 0) + bytes; + } + /* eslint-enable camelcase */ + } else { const ignored = IGNORE_PATHS.find((r) => r.test(uri)); if (bytes >= IGNORE_BYTES_UNDER && !ignored) { log.warn(`unrecognized uri: '${uri}' (${bytes} bytes)`); } - return null; - }) - .filter((r) => r); + } + } + + // insert null feeder_episodes for unknown paths under a podcast_id + for (const podcastStr in unknowns) { + if (Object.hasOwn(unknowns, podcastStr)) { + /* eslint-disable camelcase */ + const feeder_podcast = parseInt(podcastStr, 10); + const bytes = unknowns[feeder_podcast]; + usage.push({ feeder_podcast, bytes, day }); + /* eslint-enable camelcase */ + } + } + + return usage; +}; diff --git a/lib/util.test.js b/lib/util.test.js index 9fd01e6..984e022 100644 --- a/lib/util.test.js +++ b/lib/util.test.js @@ -103,5 +103,21 @@ describe("util", () => { expect(log.warn.mock.calls[0][0]).toMatch(/unrecognized uri/); expect(log.warn.mock.calls[1][0]).toMatch(/unrecognized uri/); }); + + it("combines unrecognized bytes with a null episode_id", () => { + const day = new Date("2024-03-04"); + const rows = util.parseUsage(day, [ + ["1234", "11"], + ["1234/path/is/too/long", "22"], + ["1234/path/is/much/too/long", "33"], + ]); + + expect(rows.length).toEqual(1); + expect(rows[0]).toEqual({ + feeder_podcast: 1234, + bytes: 66, + day: "2024-03-04", + }); + }); }); });