aboutsummaryrefslogtreecommitdiffstats
path: root/src/features/messages.js
Commit message (Collapse)AuthorAgeFilesLines
* Media grids: one tile for a clip uploaded twice, and a picture that won't ↵Adam Soltys30 hours1-10/+33
| | | | | | | | | | | | | | | | | | | | | | | | load stays out - Videos: one person's clips of one size to the byte are one clip. Beatbox Serenade posted the same video as a note and as a video event, each upload a fresh Blossom hash, so neither the file nor the words matched. Only a size the post or the host states counts (a bitrate x duration guess is marked sizeGuess and never matched). - Images: a picture whose load failed was hidden by a class the next repaint rewrote, so the broken-picture glyph came back (a deleted nostr.media file in #artstr). Failed pictures are now remembered for the session and left out of the grid. - A tile fetching its own frame froze the whole tile against repaints, so one built for the one-to-a-row layout never got its --ar in justified rows (zero width). Only the player and its stand-ins are frozen now; the render draws the cost badge itself. Tile pictures no longer size their tile (a frame-grab <video>'s 320px stretched its row). - Test fixtures that served one file under several names (or one imeta size for every clip) now differ per clip. Co-Authored-By: Claude Opus 5.5 <[email protected]> Claude-Session: https://claude.ai/code/session_01K5xtiFrkFVsrkWx6JDQjiT
* Videos grid: a clip the player can't load leaves the grid instead of sitting ↵Adam Soltys32 hours1-0/+12
| | | | | | | | | | | | | there as a blank tile A deleted file on Primal's blossom answers 404 without CORS headers, so the probe saw only a quiet host (not a 404), the server had no still for it, and the tile's fallback player failed with nothing listening: a blank box (Adam's iPhone). The player's error now hides the tile and marks the clip gone for a day, as a 404 the probe could read already did. Co-Authored-By: Claude Opus 5.5 <[email protected]> Claude-Session: https://claude.ai/code/session_01K5xtiFrkFVsrkWx6JDQjiT
* Videos: a desktop-sized window defaults to every shape (a phone keeps to its ↵Adam Soltys34 hours1-5/+19
| | | | | | way round; the choice is stored only when it differs from the device's default). A clip's shape falls back to its still's proportions, so leaving All shapes finds the clips known. The grid's pager keeps a clip of unknown shape out until measured, as the grid does (d898efb let an unmeasured landscape clip into a phone's vertical pager). Co-Authored-By: Claude Opus 5.5 <[email protected]>
* Images grid in justified rows too: tiles in each picture's own shape (the ↵Adam Soltys34 hours1-7/+24
| | | | | | tile thumbnail is no longer a square crop: 360px tall, its middle cut to 1:2–2:1; vmedia pic.webp?s=row for hosts without CORS; tile cache v2) Co-Authored-By: Claude Opus 5.5 <[email protected]>
* Videos grid, justified rows: a tile whose clip's size isn't known yet takes ↵Adam Soltys35 hours1-2/+16
| | | | | | its still's proportions Co-Authored-By: Claude Opus 5.5 <[email protected]>
* Videos grid, "All shapes": justified rows (each tile its clip's own ↵Adam Soltys35 hours1-5/+12
| | | | | | proportions, every row one height filling the width) instead of squares Co-Authored-By: Claude Opus 5.5 <[email protected]>
* Videos grid: "All shapes" lays the clips out three across in squares (tall ↵Adam Soltys35 hours1-4/+6
| | | | | | tiles stay for a phone held upright showing tall clips only) Co-Authored-By: Claude Opus 5.5 <[email protected]>
* Videos grid on a wide screen (wide clips only): one clip to a row with its ↵Adam Soltys35 hours1-1/+4
| | | | | | 16:9 poster whole, instead of portrait slivers three across Co-Authored-By: Claude Opus 5.5 <[email protected]>
* Videos: "All shapes" in a pager opened from the grid brings in the clips the ↵Adam Soltys35 hours1-3/+6
| | | | | | other way round (the pager now holds every clip, pagerFit keeping the wrong-shaped ones out of sight until asked) Co-Authored-By: Claude Opus 5.5 <[email protected]>
* Videos grid: a clip whose host says it's deleted (404/410) is left out for a ↵Adam Soltys35 hours1-5/+12
| | | | | | day instead of sitting there as a blank tile Co-Authored-By: Claude Opus 5.5 <[email protected]>
* Media grid shows a clip or picture once however many posts carry it (same ↵Adam Soltys35 hours1-5/+34
| | | | | | file or Blossom hash, or the same words from the same person re-uploaded); on a big window a small clip in the pager is drawn at most 1.5x its pixels instead of blown up across the monitor Co-Authored-By: Claude Opus 5.5 <[email protected]>
* Videos on a desktop: moving the mouse over a playing clip brings the seek ↵Adam Soltys35 hours1-2/+13
| | | | | | bar up, and it fades about 2 s after the mouse goes still (it stays while the pointer rests on the bar) Co-Authored-By: Claude Opus 5.5 <[email protected]>
* Replies whose post can't be found leave the Conversations view, and fewer go ↵Adam Soltys3 days1-7/+40
| | | | | | | | | | | | | | | missing A reply under "Couldn't find that note on the relays" told nobody anything (Adam, 2026-10-20), so once every lookup comes back without its post it isn't shown in a feed's Conversations view (its thread, notifications and the replier's own Replies tab keep it; a lookup that later finds the post brings it back). The lookups miss less: - A NIP-22 comment (kind 1111) names its parent's author at e-tag [3], not NIP-10's [4], so every comment's parent lost its author and the author's outbox went unasked. fiatjaf's comment on Kieran's routstr post lives on relay.snort.social (its hint), Kieran's pyramid.fiatjaf.com and ditto: none of ours. - A reply that names no author asks the outboxes of the people it's addressed to (its p tags, up to three). - The relay the reference itself names is asked even when this device has marked it sick. - A post read in Following (or the feed in use) is found in that feed's disk cache too, so a Conversations view opened right after a reload doesn't take its replies for orphans. Co-Authored-By: Claude Opus 5.5 <[email protected]> Claude-Session: https://claude.ai/code/session_013ZDf1cyCQLkfjftYhymZAg
* Timed reactions sit on the seek bar at their moment, and the usual buttons ↵Adam Soltys3 days1-35/+95
| | | | | | | | | carry the time The "at this time" reply/like/zap buttons are gone, and with them the panel they made over the pager. A reply, like or zap made from a post's own buttons (the feed's, or the pager's ♥ ⚡ and post) while its clip has played is about that moment; the reply box says so and its × makes it about the whole post. What was said, reacted or zapped at a moment sits over the bar at that moment (a custom :emoji: as its picture, from the reaction's own tag; it was showing as :cb-rofl: text), a tap goes there and says who and what, and in the pager it floats up off the bar as the clip plays past. Your reaction no longer turns the count red, only the heart. Co-Authored-By: Claude Opus 5.5 <[email protected]> Claude-Session: https://claude.ai/code/session_013ZDf1cyCQLkfjftYhymZAg
* Videos: the seek bar is out of sight (and out of reach) while a clip plays. ↵Adam Soltys4 days1-3/+15
| | | | | | | A tap near the foot of the screen brings it up for a few seconds without pausing (longer while it's dragged), and a paused clip shows it. Co-Authored-By: Claude Opus 5.5 <[email protected]> Claude-Session: https://claude.ai/code/session_013ZDf1cyCQLkfjftYhymZAg
* Videos grid: a clip opens sooner. Its host is connected to ahead (a ↵Adam Soltys4 days1-2/+52
| | | | | | | preconnect for the grid's clip hosts: the first clip from a host took 1.8 s on Adam's phone, 0.65 s once connected), and the player starts loading when the finger comes down on the tile; the pager adopts that very element, so the load overlaps the tap and the pager's opening. A press with no tap after it lets its player go. (feed-media-views test: the Live chip, and the warm next/kept previous players.) Co-Authored-By: Claude Opus 5.5 <[email protected]> Claude-Session: https://claude.ai/code/session_013ZDf1cyCQLkfjftYhymZAg
* Videos: a warm player gets its sound going before the swipe lands. On an ↵Adam Soltys4 days1-2/+38
| | | | | | | Android phone a player's first play with sound held a still picture ~250 ms while the audio output started (muted: 60 ms; a player that had played resumes in 20-80 ms). So the next clip (and the one behind) plays at a volume nobody hears until its picture moves, a frame or two in, and pauses there (a seek back to 0 undoes it). Only with the pager's sound on, and for clips up to 25 MB: once played, a player reads the whole file. Co-Authored-By: Claude Opus 5.5 <[email protected]> Claude-Session: https://claude.ai/code/session_013ZDf1cyCQLkfjftYhymZAg
* Videos: the clip just left keeps its player, so a swipe back starts at once ↵Adam Soltys4 days1-10/+16
| | | | | | | too (on Adam's phone it was the slow one: 0.66-0.78 s, built anew, against 0.04-0.08 s onto the warm next clip). The swipe clock records the player's readyState and how far it had buffered. Co-Authored-By: Claude Opus 5.5 <[email protected]> Claude-Session: https://claude.ai/code/session_013ZDf1cyCQLkfjftYhymZAg
* Videos start the moment a swipe lands, and streams say who's watching.Adam Soltys4 days1-3/+98
| | | | | | | | - The pager's next clip gets a warm player: once its opening is in the cache it reads to its first frame (preload metadata: Chrome stops ~2-4 MB in at real link speeds) and waits paused, so landing on it is only play and sound. coinosPagerStarts() in the console times every landing (swipe to moving picture, warm or cold, host, size). - A stream's "N watching" names who on hover, and a tap shows their faces: NIP-53 presence (kind 10312, as Shosho and zap.stream say it), fresh for half an hour. coinos says it too while a stream is open (every 5 min, with a key held here only, never for your own stream) and takes it back on leaving. Co-Authored-By: Claude Opus 5.5 <[email protected]> Claude-Session: https://claude.ai/code/session_013ZDf1cyCQLkfjftYhymZAg
* Posts: a relay named in a post (wss://…) is a link to what's on it — the ↵Adam Soltys4 days1-1/+9
| | | | | | | raw firehose of that relay alone (/feed/all?r=…). Trailing punctuation stays outside the link. Co-Authored-By: Claude Opus 5.5 <[email protected]> Claude-Session: https://claude.ai/code/session_013ZDf1cyCQLkfjftYhymZAg
* Profiles: past streams move off the top into a Streams tab (beside Posts and ↵Adam Soltys4 days1-11/+9
| | | | | | | Replies, shown once they've streamed), as the Live chip's grid of tiles. Co-Authored-By: Claude Opus 5.5 <[email protected]> Claude-Session: https://claude.ai/code/session_013ZDf1cyCQLkfjftYhymZAg
* Streams: Delete recording is a trash-can button and Share is the share icon ↵Adam Soltys4 days1-3/+4
| | | | | | | (three joined circles), so the stream's buttons fit on one row on a phone. Co-Authored-By: Claude Opus 5.5 <[email protected]> Claude-Session: https://claude.ai/code/session_013ZDf1cyCQLkfjftYhymZAg
* Add timestamp comments, reactions and zaps with audio waveform seekingAdam Soltys4 days1-10/+74
|
* Streams: Delete recording, and Past streams that scroll on.Adam Soltys4 days1-14/+82
| | | | | | | | | - **Delete recording:** your own ended stream's page has the button. The live server lets the recording go, and the stream is announced again without it, so other apps drop the link too. A deleted one leaves Past streams and says the streamer deleted it. - **Admin:** the Take down button no longer shows on the admin's own streams. - **Past streams** scroll on: 24 at a time as the grid's foot comes near, then older ones from the relays (before the oldest held), until a page brings nothing. They're no longer cut off at a month. Co-Authored-By: Claude Opus 5.5 <[email protected]> Claude-Session: https://claude.ai/code/session_013ZDf1cyCQLkfjftYhymZAg
* Live streams over WebRTC. Going live also sends the camera to Cloudflare's ↵Adam Soltys5 days1-3/+107
| | | | | | | | | | | | SFU, which the live server brokers, and a viewer in the app watches from there: 0.1 s behind the broadcaster in go-live-test LATENCY=1, against 3.5 s on HLS. - Switching to the screen and back swaps the track in place. - A reconnect that makes a new stream publishes again, and its viewers follow. - A viewer falls back to HLS if there's no WebRTC for the stream or no connection in 8 s. HLS is still sent, for the recording and the other nostr apps. Co-Authored-By: Claude Opus 5.5 <[email protected]> Claude-Session: https://claude.ai/code/session_013ZDf1cyCQLkfjftYhymZAg
* Notifications: tapping a zap with no post behind it does something. A zap on ↵Adam Soltys5 days1-1/+7
| | | | | | | your profile opens the zapper's profile, and a zap on a stream opens the stream. The tap used to do nothing, because the row only knew how to open a post. Co-Authored-By: Claude Opus 5.5 <[email protected]> Claude-Session: https://claude.ai/code/session_013ZDf1cyCQLkfjftYhymZAg
* Watching a stream: a stream that's on plays through hls.js, held near the ↵Adam Soltys5 days1-2/+10
| | | | | | | live edge (1.5 s back, up to 1.1× when it drifts past 5 s) — Chrome's own HLS player starts three segments back, never catches up, and fails outright (DEMUXER_ERROR_COULD_NOT_PARSE) if a page changes its speed. With the live server's 1 s segments a viewer is 3.5 s behind the broadcaster, from 8.6 s (go-live-test LATENCY=1 measures it: the broadcaster's camera is a clock in black and white blocks, read off the viewer's frame). Recordings, and streams where hls.js can't run (iOS), stay on the browser's player. Co-Authored-By: Claude Opus 5.5 <[email protected]> Claude-Session: https://claude.ai/code/session_013ZDf1cyCQLkfjftYhymZAg
* Screen sharing. In a call: Share screen in the call's bar (where the browser ↵Adam Soltys5 days1-8/+23
| | | | | | | can — desktops) puts your screen in your camera's place, or into the call if your camera's off; Stop sharing, or the browser's own, brings the camera back or stops the picture, and the other side's view follows (a picture that stops coming is hidden). Live: Share screen / Back to camera on the broadcast bar switches without stopping the stream; the browser's Stop sharing goes back to the camera instead of ending it, and a cancelled screen picker leaves the camera going. Co-Authored-By: Claude Opus 5.5 <[email protected]> Claude-Session: https://claude.ai/code/session_013ZDf1cyCQLkfjftYhymZAg
* A stream's chat is the app's chat: each comment is a bubble like a DM's or a ↵Adam Soltys5 days1-42/+152
| | | | | | | group's — tap for the emoji row, reply, zap or copy; reactions (kind 7, tagged with the stream and the comment, one per person, deletable) and zap totals show on the comment for every viewer; the zap goes to the commenter, for that comment, on that stream. The composer is the one the other chats use (drafts kept per stream). A reaction no relay took is taken back. (Begun by Codex; finished here.) Co-Authored-By: Claude Opus 5.5 <[email protected]> Claude-Session: https://claude.ai/code/session_013ZDf1cyCQLkfjftYhymZAg
* Leaving a stream: Feed (and the rest of the nav) leaves it on the first tap ↵Adam Soltys5 days1-3/+7
| | | | | | | — with the feed under the stream, Feed thought it was already there and only scrolled the hidden feed, and the nav's page-leaving didn't close the stream or Go live. On the stream's own page, the host's ringed face opens their profile instead of the same stream again. Co-Authored-By: Claude Opus 5.5 <[email protected]> Claude-Session: https://claude.ai/code/session_013ZDf1cyCQLkfjftYhymZAg
* DMs and calls go to relay.coinos.io and relay.primal.net (both take gift ↵Adam Soltys5 days1-2/+21
| | | | | | | wraps and pass call messages on live), not nos.lol, which refused or ignored the household IP's publishes. A relay that turns a call message away is left out of the next ones on this device: a day for one that won't take the kind (nip17.com: only kind 1059), ten minutes for a rate limit or ban. publishOn tells its caller which relay refused and why (onrefused). Co-Authored-By: Claude Opus 5.5 <[email protected]> Claude-Session: https://claude.ai/code/session_013ZDf1cyCQLkfjftYhymZAg
* Calls: the routes found before the offer or answer ride inside it (until ↵Adam Soltys5 days1-3/+11
| | | | | | | there's a direct and a relayed one, 1.5 s at most) and only later ones go one by one — each route was its own signed message, dozens per call; a household's two devices calling each other got its IP banned by damus and rate-limited by relay.coinos.io, and the answer was refused with them: the callee stuck on Connecting…, the caller ringing on. An offer, answer, hang-up or decline no relay took is tried again (1.5, 3, 6 s) before the call gives up. Co-Authored-By: Claude Opus 5.5 <[email protected]> Claude-Session: https://claude.ai/code/session_013ZDf1cyCQLkfjftYhymZAg
* A voice call can turn video: Turn on camera in the call's bar puts your ↵Adam Soltys5 days1-3/+7
| | | | | | | camera in (a renegotiation, NIP-AC's kind 25055); the other side sees you at once and gets the same button for theirs. The call's sound carries on throughout. Co-Authored-By: Claude Opus 5.5 <[email protected]> Claude-Session: https://claude.ai/code/session_013ZDf1cyCQLkfjftYhymZAg
* Streams on coinos's server: a ⚑ Report button (what's wrong, a note) for ↵Adam Soltys5 days1-5/+69
| | | | | | | anyone signed in, and Take down for the admin (asks whether to bar the account too); a taken-down stream says so and plays nothing. Go live asks the server first: a name claimed less than a day ago is told when it can, and a barred account that it can't, Start off. Co-Authored-By: Claude Opus 5.5 <[email protected]> Claude-Session: https://claude.ai/code/session_013ZDf1cyCQLkfjftYhymZAg
* Streams: one our live server has ended reads ended, whatever its last ↵Adam Soltys5 days1-5/+70
| | | | | | | announcement says (an app closed mid-stream never says so, and it read live for an hour with no way to stop it); its host gets End — on the stream and on their profile — which publishes the ended announcement with the recording. Each announcement is now newer than the last to the second (an ended stamped the same second as the live before it lost to it). A recording that is a web page (zap.stream's Rumble links) gets a Watch the recording link instead of a player that can't play it. Co-Authored-By: Claude Opus 5.5 <[email protected]> Claude-Session: https://claude.ai/code/session_013ZDf1cyCQLkfjftYhymZAg
* Going live: when the server can't take a dropped stream back (it restarted) ↵Adam Soltys5 days1-8/+26
| | | | | | | and starts a new one, the app now announces the new one, once it plays, and says the old one is over (no recording: there's nothing in it). It went on announcing the dead address, and viewers saw "The stream isn't playing right now" while the camera sent to an address nobody knew. The streamer's own view follows. Co-Authored-By: Claude Opus 5.5 <[email protected]> Claude-Session: https://claude.ai/code/session_013ZDf1cyCQLkfjftYhymZAg
* Past streams: under the Live chip, the feed's streams of the last month that ↵Adam Soltys5 days1-13/+60
| | | | | | | left a recording (newest first, when each ended); a profile lists its person's too. A tap plays the recording. Co-Authored-By: Claude Opus 5.5 <[email protected]> Claude-Session: https://claude.ai/code/session_013ZDf1cyCQLkfjftYhymZAg
* Live streams have their own chip, after Videos: a grid of the feed's streams ↵Adam Soltys5 days1-12/+19
| | | | | | | on now, a red dot on the chip while someone in the feed is streaming — no longer a strip above every feed's posts. Co-Authored-By: Claude Opus 5.5 <[email protected]> Claude-Session: https://claude.ai/code/session_013ZDf1cyCQLkfjftYhymZAg
* Answering a call no longer takes seconds: while it rings, the connection is ↵Adam Soltys5 days1-1/+14
| | | | | | | made with the caller's offer and its routes (TURN's too) gather, and the caller's relays and TURN credentials are looked up — Answer only adds the microphone and camera and replies (3.2 s → 0.2 s on a simulated network). An open conversation warms the same for calling out. A remote signer's offer or answer waits for a direct and a relayed route or 1.5 s, not for all of them (up to 4 s). Co-Authored-By: Claude Opus 5.5 <[email protected]> Claude-Session: https://claude.ai/code/session_013ZDf1cyCQLkfjftYhymZAg
* A call from someone you don't follow and haven't written to no longer ↵Adam Soltys5 days1-6/+34
| | | | | | | vanishes: it doesn't ring, but it's a missed call in your conversation with them, saying it didn't ring and why, a tap away from calling back (with the app shut, the worker notes it for the app, without a notification). A muted person's still leaves nothing. A logged call no longer counts as having written to someone. Co-Authored-By: Claude Opus 5.5 <[email protected]> Claude-Session: https://claude.ai/code/session_013ZDf1cyCQLkfjftYhymZAg
* Call history: each call is a row in its conversation — Outgoing / Incoming ↵Adam Soltys5 days1-3/+90
| | | | | | | video call · 4:12, Missed, Declined, No answer, Cancelled, Busy — a tap calls back. Kept like a message and sent to our own inbox (kind 1405, gift-wrapped to us alone) so our other devices list it; a call logged by two of our devices shows once, by its call-id. A call that rang while the app was shut and went unanswered is a missed call when it next opens. Co-Authored-By: Claude Opus 5.5 <[email protected]> Claude-Session: https://claude.ai/code/session_013ZDf1cyCQLkfjftYhymZAg
* Calls ring a closed app: the notifier wakes the phone for a call offer, the ↵Adam Soltys5 days1-4/+32
| | | | | | | service worker fetches the offer's wrap, opens it with your key and rings — "Alice is calling", until answered or missed — for someone you follow or talk to; the tap opens coinos ringing with the offer it kept. A call answered from a push still connects: the caller sends its candidates again once answered. Settings → Notifications → Calls. Also: the worker's DM key mirror retries when the wallet's keys aren't there yet (it waited five minutes). Co-Authored-By: Claude Opus 5.5 <[email protected]> Claude-Session: https://claude.ai/code/session_013ZDf1cyCQLkfjftYhymZAg
* Allow custom Blossom servers for attachments and post mediaAdam Soltys5 days1-2/+3
|
* Voice and video calls in DMs (NIP-AC, as Amethyst, nospeak and Noscall speak ↵Adam Soltys6 days1-6/+210
| | | | | | | it): 📞 and 🎥 in a conversation's header; a call from someone you follow or have written to rings over any page (tone, buzz, a notification when the app is out of sight) with Answer and Decline; mute, camera off, switch camera, minimize to a bar, hang up. WebRTC device to device (DTLS-SRTP), set up by signed messages in ephemeral gift wraps to the DM inboxes; TURN from coinos's live server (Cloudflare) for the connections that can't go direct. A remote signer puts the candidates inside the offer and answer instead of signing one each. Co-Authored-By: Claude Opus 5.5 <[email protected]> Claude-Session: https://claude.ai/code/session_013ZDf1cyCQLkfjftYhymZAg
* Live rings and going live. A face whose person is streaming wears a red ring ↵Adam Soltys6 days1-16/+301
| | | | | | | (LIVE under the bigger ones) and opens the stream. Go live (the composer's red dot, or your profile) sends your camera or screen to coinos's live server (coinosv3-server live/: the recording over a WebSocket, HLS out), announces it as your kind 30311 once three segments exist (Chrome's own player won't start a live playlist with fewer), refreshes it each minute with how many watch, reconnects to the same stream if the link drops, and ends it with its recording. Needs a coinos name. Also: the service worker leaves /live/ and /vmedia/hls alone (it froze a live playlist at its first copy). Co-Authored-By: Claude Opus 5.5 <[email protected]> Claude-Session: https://claude.ai/code/session_013ZDf1cyCQLkfjftYhymZAg
* Hide new posts notice when scrolling upwardAdam Soltys6 days1-9/+6
|
* Live streams (NIP-53), to watch: a row of what's on above a feed (Following: ↵Adam Soltys6 days1-15/+332
| | | | | | | your follows' streams; Everything and Popular: all), a stream's own page at /naddr1… (the HLS stream playing — hls.js where the browser has no HLS — its chat and zaps as they come, a chat line sent as kind 1311, ⚡ to the host), a card for a post linking a stream, and a LIVE line on a streamer's profile. A stream quiet for an hour is over; one that drops is retried; zaps on a stream carry its a tag. Also: the single-file build's video stub gains streamVideo (its uploads threw since the HLS uploads). Co-Authored-By: Claude Opus 5.5 <[email protected]> Claude-Session: https://claude.ai/code/session_013ZDf1cyCQLkfjftYhymZAg
* A clip in the post a reply answers (the "Replying to" card) goes full ↵Adam Soltys6 days1-4/+16
| | | | | | | screen: a tap on it or its full-screen button used to do nothing, the full-screen handler taking it back out for a media pager that doesn't have it. Co-Authored-By: Claude Opus 5.5 <[email protected]> Claude-Session: https://claude.ai/code/session_013ZDf1cyCQLkfjftYhymZAg
* The media pager no longer goes round from its last post to its first (or ↵Adam Soltys6 days1-30/+9
| | | | | | | first to last): a step, a flick or the wheel at an end stays there. Co-Authored-By: Claude Opus 5.5 <[email protected]> Claude-Session: https://claude.ai/code/session_013ZDf1cyCQLkfjftYhymZAg
* Clips too big to play as they are (past 1080p, over the data budget, ↵Adam Soltys6 days1-7/+23
| | | | | | | unmeasurable) stream as HLS from vmedia and play by themselves instead of waiting behind a tap-to-play cover; with Data Saver or a slow link the cover stays. Co-Authored-By: Claude Opus 5.5 <[email protected]> Claude-Session: https://claude.ai/code/session_013ZDf1cyCQLkfjftYhymZAg