Skip to content

Releases: datbird/couchelephant

CouchElephant 1.5.0

Choose a tag to compare

@datbird datbird released this 13 Sep 23:09

Added

  • A scheduled recording now says what settings are in force on it. Open any
    recording, from the guide, the agenda, the calendar or the recordings list,
    and the panel lists the padding, the quality and the rest in plain words:
    "Ends 60 minutes late", not endOffsetMinutes 60.

    Read from Plex's own copy of the recording rather than from what the pass
    asked for, because the point is to confirm the setting took effect. It works
    for recordings Plex scheduled by its own rule too. Opening the panel never
    waits on Plex: the values come from the copy every sync refreshes.

    A setting CouchElephant has no words for is shown with its own name and value
    rather than hidden, so a server offering something new cannot disappear from
    the one screen that exists to say what is in force.

Changed

  • The fake Plex server used by the tests answers a setting by its declared
    type. It used to return "true" for any value of 1, so a one-minute padding
    read back as true, and the panel would have said "Starts true". A fake that
    differs from the real server is as useless as one that is more permissive.

CouchElephant 1.4.0

Choose a tag to compare

@datbird datbird released this 13 Sep 21:15

The second cleanup review, over the routes, the alerts and the rest of the app.

Fixed

  • Alert times ignored the timezone setting. Every "a pass booked a
    recording at ..." line was formatted with the container's clock rather than
    the zone the app is set to. It is the one time the product quotes outside its
    own pages, and it was the one time that did not honour the setting.

  • The useful error message was on the path nobody takes. Sending and the
    Test button each carried their own list of what a destination needs, worded
    differently, and the better sentence was on the button you press once. The
    settings page renders the error from the hourly send, so the sentence you
    read when something is actually broken was the worse of the two. A bot with
    no channel now says where to find the channel id, wherever you meet it.

  • A smart pass with no name read as blank in the schedule row, the guide
    panel and the failure panel. Four places spelled the label out instead of
    calling the helper that describes the filter when there is no name.

  • The announced search wrote to the passes table directly, bypassing the
    one function whose docstring calls itself the only place a pass is written,
    after the previous three had drifted apart. It was the fourth.

  • One route answered a failure with HTTP 200, leaving the client to work it
    out from the body alone.

  • A fault code was raised as a bare string rather than its constant. Correct
    today, silently broken on a rename, and now checked by a test.

Performance

Measured against the live scale: 16,700 programmes, 22,800 airings, and a
60-day history.

  • The schedule is about four times faster. It ran the most expensive query
    in the app twice, the second time to count rows for a number no page renders.
    One row more than asked for answers the same question. The failure half also
    sorted the whole history to answer a question about broadcasts that have not
    aired yet.
  • The filter panel counted genres and teams by parsing every programme's JSON
    in Python. SQLite reads it directly, guarded so one malformed row cannot take
    the panel down, which is the behaviour the Python version had.
  • Guide search folded each title once per broadcast rather than once per
    programme.

Removed

Four pieces of dead code: a route nothing calls, an unused import, a helper
that only its own recursion used, and a function written for a provider that
was rejected and deleted. The sports source also asked its API twice for one
row, against a rate-limited free tier.

CouchElephant 1.3.1

Choose a tag to compare

@datbird datbird released this 13 Sep 20:35

Fixed

  • Upgrading to 1.3.0 announced bookings that had already been announced.
    1.3.0 re-keys existing bookings onto the new airing id. The alert state is
    keyed on that same id, and it was not re-keyed with them, so the next
    dispatch read a booking nobody had heard about and said so again. Seen on a
    live install: two recordings booked days earlier were announced a second time
    at the moment of the upgrade.

    The whole rule notify_state runs on is that a row exists means this
    destination has been told, and the migration broke the key that rule depends
    on. Both are now re-keyed together, state first.

    Nothing was booked twice and no recording was affected. Only the messages
    were duplicated.

CouchElephant 1.3.0

Choose a tag to compare

@datbird datbird released this 13 Sep 20:18

A cleanup review of sync.py and passes.py found the cause under four fixes
that shipped this week, two silences, and two bugs nobody had reached yet.

Fixed

  • A broadcast's id is now minted from the broadcast. It used to prefer
    Plex's own Media.id, which is the one value in the payload that moves: a
    guide refresh renumbers airings without changing anything about them, and one
    game here collected nine ids over three weeks. Every lookup keyed on the id
    had to be taught to resolve a retired one, and four of them were taught one at
    a time, each after failing in front of somebody.

    An id is now the programme, the channel and the start time. A renumber
    produces the same id. A re-time still changes it, which is correct: that is a
    different broadcast and the app has to notice. Bookings made before this are
    re-keyed when the app starts.

    Two more places had the same fault and nobody had reached them. The guide's
    "Being recorded" filter stopped matching a booked game after a refresh, and
    cancelling a recording by hand answered "CouchElephant did not schedule this"
    for a recording CouchElephant had scheduled.

  • A re-point that Plex refused was counted and never mentioned. It
    incremented the failure count without adding to the list the notices are
    built from, so nothing was raised. That is the silence this whole check
    exists to remove.

  • A booking could be trapped in a permanent failure. Plex was asked about
    the subscription before our own guide was consulted, so a booking whose
    subscription Plex had lost and whose broadcast had left the guide went to the
    re-book path. There is nothing to re-book from, so it failed and raised a
    notice on every sync, for ever, while the branch that exists to cancel
    exactly that booking was unreachable for it.

  • A repaired booking's history row could name two broadcasts at once,
    recording the old airing id beside the new channel and start time.

Changed

  • One re-book path instead of two. They had already disagreed about when to
    forget the old booking and whether to write down a failure.
  • Guide and schedule pulls share one prune helper rather than two copies.
  • The booking check counts in one place, so a new outcome cannot be counted in
    one half and forgotten in the other.

Performance

Measured against the live install: about 16,700 programmes and 22,800 airings
per sync, hourly.

  • A channel is written once per sync instead of once per broadcast: about
    22,700 redundant writes and the same number of redundant title parses, gone.
  • Two indexes on plex_grabs, which holds the whole DVR schedule and was
    scanned in full by three hot questions, one of them once per airing of a
    programme.
  • Asking whether a team pass matches anything now stops at the first match
    instead of hydrating every match in the window.
  • Re-pointing a booking asks for one programme in SQL rather than the pass's
    whole thirty-day window, and reads the pass rows once per check rather than
    once per booking.
  • A pass run reads the last sync time once rather than once per game.

CouchElephant 1.2.12

Choose a tag to compare

@datbird datbird released this 13 Sep 17:25

Fixed

  • Clicking a recording could open a panel reading "not found". A booking
    stores the airing id it was made against, and the schedule row carried that
    id straight through. A guide refresh mints new ids for broadcasts that have
    not changed at all, so the stored one retires and the row points at nothing.
    The recording was perfectly fine; only the link was stale, and refreshing the
    page did not help because the row was rebuilt from the same stored id.

    A row now names the broadcast the guide holds now. A broadcast that really
    has gone says so in words, rather than "not found", because that reads as a
    broken page and the usual cause is not a broken page.

CouchElephant 1.2.11

Choose a tag to compare

@datbird datbird released this 13 Sep 17:07

Changed

  • A settings change is now made on the recording Plex already holds, so it
    has no deadline.
    Changing a pass used to cancel each recording it had
    booked and make it again, even to move one number. That has a moment in the
    middle with nothing scheduled, so it was refused within two sync intervals of
    the broadcast. The result was that the padding could not be corrected at the
    one time somebody usually notices it is wrong, which is shortly before the
    game.

    Plex takes a partial update on a subscription that exists:
    PUT /media/subscriptions/<key> with the settings to change. The pin is
    untouched and the scheduled recording survives, verified against a live
    server. Only the settings that actually differ are sent, and they can only be
    settings the server itself reported, so nothing here can send a setting the
    booking will not take.

    Booking again is still what happens when the guide has moved the broadcast
    under a booking, when Plex has lost the subscription, or when it has
    scheduled nothing against it. Those keep the timing guard, because they are
    the ones with a gap. An edit that somehow leaves nothing scheduled falls back
    to booking again as well.

CouchElephant 1.2.10

Choose a tag to compare

@datbird datbird released this 13 Sep 16:15

Fixed

  • A booking stopped being checked the first time Plex renumbered its guide.
    A guide refresh mints new airing ids for broadcasts that have not changed at
    all: same channel, same time, new id. One game here collected nine ids over
    three weeks. A booking was read only by the id it had stored, so after a
    renumber it was quietly skipped, and every later change to its pass missed it
    with nothing said. Found on a live DVR with one of two recordings already in
    that state.

    A booking is now looked up by its id first and by the broadcast it was made
    against second, and a repair re-books from whichever id the guide holds now.

CouchElephant 1.2.9

Choose a tag to compare

@datbird datbird released this 13 Sep 15:51

Fixed

  • Changing a pass did not change the recordings it had already booked.
    Saving a pass booked any new games and stopped there, so a recording already
    on the DVR kept the settings it was made with until the next sync, up to an
    hour later. The page said one thing and the DVR did another, and a game
    inside that hour was never corrected at all: by then it is too close to
    kickoff to re-book safely.

    The booking check now runs when a pass is saved as well as on every sync. It
    refreshes the copy of Plex's schedule first, so a recording booked minutes
    ago is not read as one Plex has scheduled nothing for and cancelled. The
    reply says how many existing recordings were updated, and how many were left
    alone for being too close to their broadcast.

    The pass is saved whatever Plex is doing. A server unreachable for a moment
    never fails the save, and the next sync carries the change.

CouchElephant 1.2.8

Choose a tag to compare

@datbird datbird released this 13 Sep 08:24

Changed

  • The Notifications page says what a relay is for, and the documentation
    screenshots show one. A destination nobody can tell apart from the others is
    a destination nobody picks.

CouchElephant 1.2.7

Choose a tag to compare

@datbird datbird released this 13 Sep 08:08

Added

  • A relay on your own network as an alert destination, speaking timmyd's
    /notify. It is the only destination that names no channel. It is handed the
    severity and decides for itself, so a fault lands in the channel you watch
    while a recording that started, a pass that booked something, or a fault that
    cleared lands in the one you read later. Nothing is configured twice and this
    end never learns which channels exist.

    The address is checked as an ordinary http or https address with a host and no
    credentials in it, and deliberately not against a host allowlist: a relay is a
    service you run, usually on the same network as this container, so there is
    nothing to pin it to. Plain http is allowed for the same reason.

    The relay answers 202 once it has queued a message and 503 when its queue is
    full, both with ok in the body. Queued is not delivered, and it is the
    strongest thing a relay can honestly say, but a 2xx alone still proves
    nothing, so the body is what is believed and a refusal is never recorded as
    sent.

Changed

  • A destination's address is only masked when the address is itself the
    credential. A Discord webhook URL still is, so it stays masked. A relay's
    address is a machine on your network, and masking it only hid which relay a
    destination pointed at.

Fixed

  • A subscription this app had just cancelled survived in its copy of Plex's
    schedule.
    Our copy was pruned by timestamp, so two pulls inside one second
    kept every row the first one wrote. A stale row then read as a live booking,
    and a pass would skip a game nothing was recording. Both the subscription and
    the grab lists are now pruned by what the pull actually saw. Same fault as the
    guide prune in 1.2.6, in the other mirror.