feat(player): the OS media controls, the basic keys and resume for the library and shared-link players
Plex, library and /watch tell the operating system what plays (title, line, picture) and take its
play / pause / skip / seek through one hook (lib/mediaSession); the Plex player drives it with its own
seek and clock, so the lock screen shows the film's position, not the stream's. The YouTube player is
left alone: its iframe already publishes all of it, and the OS routes to the frame that plays.
The library and /watch players get the basic keys (lib/mediaKeys, the keymap's mediaPlayer rows) and
open where the viewer stopped (lib/resume): the library keeps the point on the server, per user and
library item (library_states, POST /api/downloads/{id}/progress, listed back on both listings), the
shared link in this browser. A started library row continues, its menu can start it over, and its
picture carries the cards' progress bar. The resume rule (too early / near the end = from the start)
is one function shared with the YouTube route.
The library dialog opens focused on its panel (Modal initialFocus "player"): on the ✕, Space closed
the film. While the media element itself has the focus, Space and the arrows stay its own controls'
— the browser acts on them whatever a listener does, and one Space played and paused.
This commit is contained in:
@@ -23,7 +23,10 @@ def client(monkeypatch, override_dep) -> TestClient:
|
||||
return TestClient(app)
|
||||
|
||||
|
||||
@pytest.mark.parametrize("path", ["/api/videos/v1/progress", "/api/plex/item/98614/progress"])
|
||||
@pytest.mark.parametrize(
|
||||
"path",
|
||||
["/api/videos/v1/progress", "/api/plex/item/98614/progress", "/api/downloads/1/progress"],
|
||||
)
|
||||
@pytest.mark.parametrize("raw", ["Infinity", "-Infinity", "NaN"])
|
||||
def test_a_non_finite_position_is_refused(client, path, raw):
|
||||
r = client.post(
|
||||
@@ -34,7 +37,10 @@ def test_a_non_finite_position_is_refused(client, path, raw):
|
||||
assert r.status_code == 422, r.text
|
||||
|
||||
|
||||
@pytest.mark.parametrize("path", ["/api/videos/v1/progress", "/api/plex/item/98614/progress"])
|
||||
@pytest.mark.parametrize(
|
||||
"path",
|
||||
["/api/videos/v1/progress", "/api/plex/item/98614/progress", "/api/downloads/1/progress"],
|
||||
)
|
||||
@pytest.mark.parametrize("field", ["position_seconds", "duration_seconds"])
|
||||
def test_a_position_past_the_int4_column_is_refused_not_a_500(client, path, field):
|
||||
"""Finite but past the int4 column: the flush was a DataError, i.e. a 500 with a traceback."""
|
||||
|
||||
Reference in New Issue
Block a user