Add the Live Tennis plugin - #330
Open
bensynapse wants to merge 2 commits into
Open
Conversation
Live tennis scores on a key: both players' surnames, the set score, the points in the current game, a marker beside the server and a marker on the side holding a break point. ATP, WTA, Challenger, ITF and juniors. Complementary to SportsScores rather than competing with it: that plugin covers the US leagues and soccer and has no tennis, this one has nothing but tennis. Data comes from the Live Tennis API, which the plugin author operates; the plugin needs a key, and a free key covers everything it does. Both endpoints it uses are on the free tier. The free tier allows 100 requests a day, so the plugin defaults to a 15-minute refresh (96 requests a day) with 15 minutes as a hard floor clamped in code, and every key showing tennis shares one cached request. The hash is the plugin repo's commit; entry follows the live shape in this file rather than the 'commits' map still shown in the submission docs.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Disclosure first: this plugin reads the Live Tennis API, a commercial service I operate. I am submitting a plugin for my own API and I want that on the record before anything else. The plugin bundles no data and contacts nothing else: no telemetry, no analytics. It needs an API key, and a free key with no card covers everything it does, because both endpoints it uses are on the free tier. It never requests a paid endpoint. If a vendor-operated plugin is not something you want in the store, say so and I will close this without argument. AI tooling was used while writing it; the code and the checks below are mine.
Complementary to SportsScores, not competing with it.
Mattdubs9699/SportsScorescovers the US leagues, the college leagues and soccer, and has no tennis. This has nothing but tennis: ATP, WTA, Challenger, ITF and juniors, singles and doubles. There is no overlap in leagues, actions or settings, and the README points users at SportsScores for everything this does not do. Run both.What it does
One action, Live Tennis Match, draws a live match on a key:
The key goes red while the receiver holds a break point, so it reads across a room. Break point is derived, not served: the receiver at advantage, or the receiver at 40 while the server is at 0, 15 or 30. Never in a tiebreak, where there is no service game to break and the points are a running count rather than tennis scores. Optional filters pin a key to one player or one tour, and a short press asks for a refresh.
On request rate, since a scores plugin is the obvious place to get this wrong
A free key allows 100 requests a day. So the refresh interval defaults to 15 minutes, which is 96 requests a day with four spare, and 15 minutes is a hard floor clamped in code rather than merely the spin box's minimum. A hand-edited settings file is clamped on read and on write, and the HTTP layer independently refuses a second call for the same data inside the floor, counted from the last attempt so a failing endpoint cannot retry-loop either.
Every Live Tennis key reads one shared in-memory cache, so six keys showing six different matches still cost one request per refresh. Adding keys can never raise the rate.
For contrast, a 15-second cadence would want 5,760 requests a day and would spend a free key's entire budget in 25 minutes, after which every tennis key on the deck goes blank until the quota resets. A failed refresh keeps the last score rather than blanking the key.
The API key lives in the plugin's own settings behind a password entry row, shared by every action. It is never hardcoded, travels as a header rather than in a URL, and is kept out of every log line and error string.
Housekeeping
GPL-3.0-or-later, matching StreamController.
manifest.json,actions.json,attribution.json,VERSIONandrequirements.txtare all present, and the artwork is drawn for the plugin with no third-party assets.One small thing you may want to fix: the entry below follows the shape of the live
Plugins.json, which isurlplushash. Yourdocs/plugin_dev/submitting/submitting.mdstill shows acommitsmap instead, and none of the 73 existing entries use it.Verification
The plugin compiles on Python 3,
ruff checkis clean, and every JSON file in both this repo and the plugin parses. A logic harness covering 142 checks passes: break-point derivation across the point pairs and tiebreaks, player-major set-score formatting, the nullable score shapes the API returns on a completed match, the cadence clamp, the shared cache proving six keys cost one request, the key travelling as a header and never appearing in an error string, and each HTTP status mapping to a short label.What I could not verify: StreamController is not installed on the machine I built this on, so the plugin has never been loaded in the app and no widget was ever realised. The framework symbols were each confirmed against your source, but not exercised. I also made no authenticated API call, so field shapes come from our published OpenAPI document rather than an observed payload.