Commits
Wrapped cloudflared install in function so local variables are valid.…
The daemon asks GitHub once a day whether a newer release exists, twenty
seconds after startup so it never competes with the window or the
recorder. When there is one, a card shows the version, a few lines lifted
from the release notes, and the right update command for how this machine
installed Vice, using the detection that already existed for uninstall.
It is built not to nag. One request a day at most, conditional on the
cached etag. Nothing is shown unless the release is strictly newer than
what is installed, so a development build ahead of the newest tag stays
quiet. Drafts and prereleases are ignored. Dismissing hides the card for
that version for good and leaves only a small chip in the top bar, and
the flag is stored server side so a webview storage reset cannot bring it
back. Every failure path is silent, and the whole thing is one toggle in
Settings.
The window used to be watched assembling itself: an empty grid, then
stats, then playlists popping in. A splash now covers the first paint and
lifts only once the config, clips and playlists have landed and painted
underneath, with a timer behind it so a slow or dead daemon can never
leave the window stuck.
The sidebar's glass is now one shared recipe rather than values copied
per element, and the editor panels use it, so they are genuinely the same
surface. Floating surfaces that sit over real content (modals, the
player, the quit pill, toasts, popovers) keep their own recipe, but
without backdrop blur they now carry a themed gradient instead of a flat
navy fill. That matters more than it sounds: on a machine that falls back
to software compositing, that fallback is what the user sees all the
time, not an edge case.
QtWebEngine cannot initialise GBM on NVIDIA and prints "GBM is not
supported with the current configuration. Fallback to Vulkan rendering in
Chromium." on every launch. That line announces a fallback, it does not
report a failure, but it was treated as an immediate fatal signal and the
app relaunched itself with software compositing before the window ever
had a chance to render. Vulkan was also blocked on every NVIDIA machine,
which disabled the exact fallback the message was announcing, so the only
remaining GPU path was gone.
The GBM line now triggers nothing. The repeating black window markers
still do, at their existing threshold, so a genuine failure is still
caught and still falls back for that run only. Vulkan is blocked only
below driver 550, the series it actually segfaulted on (#82), and an
unreadable driver version no longer downgrades the machine.
Verified on an RTX 4060 with driver 610 under Hyprland: the window
renders at full GPU with no black window markers at all.
A full multi-track editor: drag clips from a searchable library onto
video, audio and title tracks, trim and split them, drop transitions
between them, and burn in titles.
Export renders the whole timeline in one ffmpeg pass. Every video track
is built the same way, so a clip on an upper track gets the same real
transitions the program track does: segments and gap fillers joined by
concat, with xfade at the junctions and the outgoing side extended by the
transition length so absolute timeline positions never shift. Upper
tracks fill their gaps transparently and composite with overlay, which is
what lets the tracks below show through. Dip to accent has no xfade
equivalent and renders as colour fades around a hard cut.
Titles are drawn with drawtext reading the text from a sidecar file, so a
percent sign in a title cannot blank the line, and static TTFs are
shipped because drawtext cannot read the woff2 the UI uses.
The preview plays the real clips: three video elements per track bound
per frame to the current, outgoing and upcoming clips, so a run of
transitions never tears down a decoder it is about to need again. The
clock follows the visible video rather than the wall clock, which is what
keeps playback smooth across cuts.
Projects autosave server side and follow clips through renames and
deletes, and exports can go to the library or anywhere else on disk.
Auto per-game playlists were read-only. You can now rename, recolour and set an
emoji on them, delete them, and drag any clip in or add it by right-click, the
same as custom playlists. An edited auto playlist keeps auto-filing new clips of
its game and is no longer pruned when it empties. Deleting one sticks across
restarts (it isn't rebuilt from tagged clips) but clipping that game again
revives it. Same-game clips still land in the existing playlist, never a
duplicate.
Changing a recording setting builds a new recorder, but the code only re-wired
on_clip_saved, not clip_tag_cb, so after any settings edit clips saved untagged
and no per-game playlist was created (both depend on the tag callback running).
Wire both through one _wire_recorder helper so they can't drift again, and log
the detected window and match per clip so a missed game is easy to diagnose.
Also adds a 'Create a playlist per game' toggle (output.auto_playlist_by_game,
default on) gating the auto playlists independently of filename tagging.
Probe HEVC decode support, route the viewer, trim and mini player through the
proxy when the engine can't play the codec, and show a brief preparing-preview
state while the daemon transcodes.
H.265 clips (NVENC/VAAPI) can't play in the native window, which also made
them impossible to trim. The clip payload now carries the video codec, and
/v/<slug>?proxy=1 transcodes a cached H.264 copy on demand. The original stays
H.265 and trims still cut the original, so there's no quality loss. Proxies are
keyed by file identity and cleared on delete, rename and trim.
Copy-to-clipboard (link and the new copy-file button) fell back to the manual
modal on the AUR package because wl-clipboard/xclip were only optdepends, and
the public tunnel silently stayed on the LAN because cloudflared wasn't pulled
in. Promote all three to depends so both work out of the box.
The clip card's plus button is now a copy-to-clipboard button; add-to-playlist
moved to right-click and dragging a clip onto a sidebar playlist, with a small
drag chip instead of a full-size card. Adds the accent-tinted gradient backdrop
to the quit pill, clip viewer and mini player, a clip filename template field
with a live preview, and the LAN-only link warning.
Adds the missing dnf build deps (gcc-c++, libva, vulkan, libcap), retries
package installs one at a time so one bad name doesn't sink the whole build,
uses the right QtPy casing and cloudflared arch, and drops the stale serveo
mention. Startup crashes now lead with a readable cause for known errors
like 'failed to load opengl' instead of a bare traceback.
- Copy a clip file to the clipboard (text/uri-list) so it pastes into Discord
- Flag share links that only work on the local network
- Store the first-run tutorial flag server-side so it survives webview resets
- Stop purging view counts on startup; they now persist like highlights and
are only cleared on delete or when a clip number is reused
Moving a volume slider off 100% made GSR record desktop and mic as separate
tracks, but the trim and watermark passes ran ffmpeg with no -map, so the
default single-stream pick dropped the mic. Map all streams through every
pass and skip the volume mix when custom audio tracks are set.
Also adds an optional clip filename template ($n/$date/$time/$game, empty
keeps the default naming) and bumps the default clip length to 20 seconds.
Views are counted server-side per clip when it is freshly loaded into the
viewer, stored beside the highlights data, and follow the clip through
renames and deletions like playlist membership does. The home rows now
render as many cards as fit the window width, and custom playlists gained
an Edit flow reusing the creation modal over the existing PATCH endpoint.
Liquid-glass look: a floating rounded sidebar with search and playlists,
a drifting accent-tinted gradient background, glass cards with individual
sheens, a larger viewer paired with a mini player bar that rises to sit
under it, restyled settings, about, and trim, and a second tutorial page
covering playlists. Accent themes now retint the whole window including
the ambient glows. Software-rendering mode keeps the gradient and tinted
panels while dropping only the per-frame backdrop blur.
Clips are grouped into a persisted server-side store: auto playlists are
created when a game is detected at clip-save time (independent of the
filename tag setting, with a startup backfill from existing tags), and
custom playlists are managed over a new /api/playlists surface. Membership
is keyed by clip slug and updated inside the same handlers that rename and
delete clips, so playlists survive renames, trims, and deletions.
Hotkeys can now be a modifier combo like Alt+F9, not just a single key.
The evdev listener tracks held modifiers and matches the full chord;
left/right modifiers fold together and press order does not matter.
Bare single-key binds are unchanged.
Active-window detection now falls back to the X11 adapter over XWayland
on non-Hyprland/Sway Wayland sessions (KDE Plasma, GNOME), so Discord
Rich Presence and game tagging pick up XWayland games there.
Fixes #101, #102
twitter:player must point at an embeddable HTML page, but the embed
page handed Discord the raw mp4. Discord prefers the player card over
og:video and does not iframe arbitrary players, so an unusable player
meant no embed at all, just a bare link. Serve plain OpenGraph video
metadata instead, the pattern working self-hosted sharers use, with
og:url and a direct file URL carrying the real container suffix.
Issue #77, Issue #100
cloudflared's startup banner contains other *.cloudflare.com links
(docs, downloads). The old line scan accepted any of them as the
tunnel URL, so share links could point at the Cloudflare docs site.
Match https://<name>.trycloudflare.com exactly and keep the first
match.
Also honor X-Forwarded-Proto on the embed page. cloudflared
terminates TLS and forwards plain HTTP, so og:video URLs came out as
http:// and Discord refused to embed them.
Issue #100
Home recent cards reuse cardHTML, so grid cards and home cards share
card-<slug> ids. startRename resolved the card with getElementById,
which returned the hidden home card: the rename input went into a view
the user could not see, and the next click threw on the missing
.clip-name. Pass the clicked element and use closest('.clip-card'),
and bail out cleanly if a rename is already in progress.
Issue #99
config.load() passed every key in config.toml straight into the
dataclass constructors, so a config written by a newer Vice took older
daemons down with a TypeError at startup. 1.2.x crashed on sight of the
recording keys 1.3.0 added. Unknown keys are now dropped with a logged
warning, the same way the settings API already handled them.
The audio source pickers refresh when the settings view opens and on
demand via a refresh button, so apps that start playing audio later
show up without restarting Vice. Separate audio tracks can be
reordered with arrows and show friendly device names instead of raw
ids.
The mic toggle now records the configured microphone_source instead of
always the system default input, and with separate tracks set the mic
is added as its own track (it was silently dropped before). Turning
desktop audio off now also silences configured tracks.
New audio_tracks_mix_first option records an extra track 1 that mixes
every source, so players, Discord, and shared clips carry full audio
while the separate tracks stay editable. Audio/display enumeration
moved off the event loop.
Issue #98
The PyPI PyQt6-WebEngine wheel ships without proprietary codecs, so it
cannot decode H.264 at all. Installs that fell back to the wheel played
every clip as a silent grey rectangle: the audio track decodes, the video
track is silently dropped (videoWidth stays 0), and no error event fires.
- Probe H.264 support at startup; show a banner with the distro fix when
the engine cannot decode clips at all
- Detect per-video failures (error events and the no-video-track case) in
the viewer, trim modal, and hover previews; show an explanatory overlay
instead of silent grey, with Open in system player / Show in folder
- New POST /api/clips/{slug}/open endpoint (local-only): xdg-open the clip
- Serve .mkv clips as video/x-matroska instead of claiming video/mp4
- install.sh: loud warning when the system WebEngine package is missing
and the PyPI wheel will be used, repeated at the end of the install
- README troubleshooting entry
Issue #79
The recorder identified GSR's flushed replay by diffing the clips folder
against a baseline captured at recorder start. Any file that appeared in
between (a finished session recording, a clip renamed in the UI, a late
flush from a timed-out save) was claimed as the new clip on the next
hotkey press, then renamed, trimmed, and shown in place of the real one.
The baseline is now snapshotted immediately before each flush trigger,
and Vice-named files (sequential clips, sessions, edit temp files) are
never treated as GSR output.
Separately, deleted clip numbers get reused (a new clip can become
Vice_Clip_5 again) and trims rewrite files in place, so the webview
could play a cached older video for the clip it shows. Video URLs are
now versioned by file identity and /v/ responses revalidate (no-cache).
The daemon asks GitHub once a day whether a newer release exists, twenty
seconds after startup so it never competes with the window or the
recorder. When there is one, a card shows the version, a few lines lifted
from the release notes, and the right update command for how this machine
installed Vice, using the detection that already existed for uninstall.
It is built not to nag. One request a day at most, conditional on the
cached etag. Nothing is shown unless the release is strictly newer than
what is installed, so a development build ahead of the newest tag stays
quiet. Drafts and prereleases are ignored. Dismissing hides the card for
that version for good and leaves only a small chip in the top bar, and
the flag is stored server side so a webview storage reset cannot bring it
back. Every failure path is silent, and the whole thing is one toggle in
Settings.
The window used to be watched assembling itself: an empty grid, then
stats, then playlists popping in. A splash now covers the first paint and
lifts only once the config, clips and playlists have landed and painted
underneath, with a timer behind it so a slow or dead daemon can never
leave the window stuck.
The sidebar's glass is now one shared recipe rather than values copied
per element, and the editor panels use it, so they are genuinely the same
surface. Floating surfaces that sit over real content (modals, the
player, the quit pill, toasts, popovers) keep their own recipe, but
without backdrop blur they now carry a themed gradient instead of a flat
navy fill. That matters more than it sounds: on a machine that falls back
to software compositing, that fallback is what the user sees all the
time, not an edge case.
QtWebEngine cannot initialise GBM on NVIDIA and prints "GBM is not
supported with the current configuration. Fallback to Vulkan rendering in
Chromium." on every launch. That line announces a fallback, it does not
report a failure, but it was treated as an immediate fatal signal and the
app relaunched itself with software compositing before the window ever
had a chance to render. Vulkan was also blocked on every NVIDIA machine,
which disabled the exact fallback the message was announcing, so the only
remaining GPU path was gone.
The GBM line now triggers nothing. The repeating black window markers
still do, at their existing threshold, so a genuine failure is still
caught and still falls back for that run only. Vulkan is blocked only
below driver 550, the series it actually segfaulted on (#82), and an
unreadable driver version no longer downgrades the machine.
Verified on an RTX 4060 with driver 610 under Hyprland: the window
renders at full GPU with no black window markers at all.
A full multi-track editor: drag clips from a searchable library onto
video, audio and title tracks, trim and split them, drop transitions
between them, and burn in titles.
Export renders the whole timeline in one ffmpeg pass. Every video track
is built the same way, so a clip on an upper track gets the same real
transitions the program track does: segments and gap fillers joined by
concat, with xfade at the junctions and the outgoing side extended by the
transition length so absolute timeline positions never shift. Upper
tracks fill their gaps transparently and composite with overlay, which is
what lets the tracks below show through. Dip to accent has no xfade
equivalent and renders as colour fades around a hard cut.
Titles are drawn with drawtext reading the text from a sidecar file, so a
percent sign in a title cannot blank the line, and static TTFs are
shipped because drawtext cannot read the woff2 the UI uses.
The preview plays the real clips: three video elements per track bound
per frame to the current, outgoing and upcoming clips, so a run of
transitions never tears down a decoder it is about to need again. The
clock follows the visible video rather than the wall clock, which is what
keeps playback smooth across cuts.
Projects autosave server side and follow clips through renames and
deletes, and exports can go to the library or anywhere else on disk.
Auto per-game playlists were read-only. You can now rename, recolour and set an
emoji on them, delete them, and drag any clip in or add it by right-click, the
same as custom playlists. An edited auto playlist keeps auto-filing new clips of
its game and is no longer pruned when it empties. Deleting one sticks across
restarts (it isn't rebuilt from tagged clips) but clipping that game again
revives it. Same-game clips still land in the existing playlist, never a
duplicate.
Changing a recording setting builds a new recorder, but the code only re-wired
on_clip_saved, not clip_tag_cb, so after any settings edit clips saved untagged
and no per-game playlist was created (both depend on the tag callback running).
Wire both through one _wire_recorder helper so they can't drift again, and log
the detected window and match per clip so a missed game is easy to diagnose.
Also adds a 'Create a playlist per game' toggle (output.auto_playlist_by_game,
default on) gating the auto playlists independently of filename tagging.
H.265 clips (NVENC/VAAPI) can't play in the native window, which also made
them impossible to trim. The clip payload now carries the video codec, and
/v/<slug>?proxy=1 transcodes a cached H.264 copy on demand. The original stays
H.265 and trims still cut the original, so there's no quality loss. Proxies are
keyed by file identity and cleared on delete, rename and trim.
The clip card's plus button is now a copy-to-clipboard button; add-to-playlist
moved to right-click and dragging a clip onto a sidebar playlist, with a small
drag chip instead of a full-size card. Adds the accent-tinted gradient backdrop
to the quit pill, clip viewer and mini player, a clip filename template field
with a live preview, and the LAN-only link warning.
Adds the missing dnf build deps (gcc-c++, libva, vulkan, libcap), retries
package installs one at a time so one bad name doesn't sink the whole build,
uses the right QtPy casing and cloudflared arch, and drops the stale serveo
mention. Startup crashes now lead with a readable cause for known errors
like 'failed to load opengl' instead of a bare traceback.
- Copy a clip file to the clipboard (text/uri-list) so it pastes into Discord
- Flag share links that only work on the local network
- Store the first-run tutorial flag server-side so it survives webview resets
- Stop purging view counts on startup; they now persist like highlights and
are only cleared on delete or when a clip number is reused
Moving a volume slider off 100% made GSR record desktop and mic as separate
tracks, but the trim and watermark passes ran ffmpeg with no -map, so the
default single-stream pick dropped the mic. Map all streams through every
pass and skip the volume mix when custom audio tracks are set.
Also adds an optional clip filename template ($n/$date/$time/$game, empty
keeps the default naming) and bumps the default clip length to 20 seconds.
Views are counted server-side per clip when it is freshly loaded into the
viewer, stored beside the highlights data, and follow the clip through
renames and deletions like playlist membership does. The home rows now
render as many cards as fit the window width, and custom playlists gained
an Edit flow reusing the creation modal over the existing PATCH endpoint.
Liquid-glass look: a floating rounded sidebar with search and playlists,
a drifting accent-tinted gradient background, glass cards with individual
sheens, a larger viewer paired with a mini player bar that rises to sit
under it, restyled settings, about, and trim, and a second tutorial page
covering playlists. Accent themes now retint the whole window including
the ambient glows. Software-rendering mode keeps the gradient and tinted
panels while dropping only the per-frame backdrop blur.
Clips are grouped into a persisted server-side store: auto playlists are
created when a game is detected at clip-save time (independent of the
filename tag setting, with a startup backfill from existing tags), and
custom playlists are managed over a new /api/playlists surface. Membership
is keyed by clip slug and updated inside the same handlers that rename and
delete clips, so playlists survive renames, trims, and deletions.
Hotkeys can now be a modifier combo like Alt+F9, not just a single key.
The evdev listener tracks held modifiers and matches the full chord;
left/right modifiers fold together and press order does not matter.
Bare single-key binds are unchanged.
Active-window detection now falls back to the X11 adapter over XWayland
on non-Hyprland/Sway Wayland sessions (KDE Plasma, GNOME), so Discord
Rich Presence and game tagging pick up XWayland games there.
Fixes #101, #102
twitter:player must point at an embeddable HTML page, but the embed
page handed Discord the raw mp4. Discord prefers the player card over
og:video and does not iframe arbitrary players, so an unusable player
meant no embed at all, just a bare link. Serve plain OpenGraph video
metadata instead, the pattern working self-hosted sharers use, with
og:url and a direct file URL carrying the real container suffix.
Issue #77, Issue #100
cloudflared's startup banner contains other *.cloudflare.com links
(docs, downloads). The old line scan accepted any of them as the
tunnel URL, so share links could point at the Cloudflare docs site.
Match https://<name>.trycloudflare.com exactly and keep the first
match.
Also honor X-Forwarded-Proto on the embed page. cloudflared
terminates TLS and forwards plain HTTP, so og:video URLs came out as
http:// and Discord refused to embed them.
Issue #100
Home recent cards reuse cardHTML, so grid cards and home cards share
card-<slug> ids. startRename resolved the card with getElementById,
which returned the hidden home card: the rename input went into a view
the user could not see, and the next click threw on the missing
.clip-name. Pass the clicked element and use closest('.clip-card'),
and bail out cleanly if a rename is already in progress.
Issue #99
config.load() passed every key in config.toml straight into the
dataclass constructors, so a config written by a newer Vice took older
daemons down with a TypeError at startup. 1.2.x crashed on sight of the
recording keys 1.3.0 added. Unknown keys are now dropped with a logged
warning, the same way the settings API already handled them.
The audio source pickers refresh when the settings view opens and on
demand via a refresh button, so apps that start playing audio later
show up without restarting Vice. Separate audio tracks can be
reordered with arrows and show friendly device names instead of raw
ids.
The mic toggle now records the configured microphone_source instead of
always the system default input, and with separate tracks set the mic
is added as its own track (it was silently dropped before). Turning
desktop audio off now also silences configured tracks.
New audio_tracks_mix_first option records an extra track 1 that mixes
every source, so players, Discord, and shared clips carry full audio
while the separate tracks stay editable. Audio/display enumeration
moved off the event loop.
Issue #98
The PyPI PyQt6-WebEngine wheel ships without proprietary codecs, so it
cannot decode H.264 at all. Installs that fell back to the wheel played
every clip as a silent grey rectangle: the audio track decodes, the video
track is silently dropped (videoWidth stays 0), and no error event fires.
- Probe H.264 support at startup; show a banner with the distro fix when
the engine cannot decode clips at all
- Detect per-video failures (error events and the no-video-track case) in
the viewer, trim modal, and hover previews; show an explanatory overlay
instead of silent grey, with Open in system player / Show in folder
- New POST /api/clips/{slug}/open endpoint (local-only): xdg-open the clip
- Serve .mkv clips as video/x-matroska instead of claiming video/mp4
- install.sh: loud warning when the system WebEngine package is missing
and the PyPI wheel will be used, repeated at the end of the install
- README troubleshooting entry
Issue #79
The recorder identified GSR's flushed replay by diffing the clips folder
against a baseline captured at recorder start. Any file that appeared in
between (a finished session recording, a clip renamed in the UI, a late
flush from a timed-out save) was claimed as the new clip on the next
hotkey press, then renamed, trimmed, and shown in place of the real one.
The baseline is now snapshotted immediately before each flush trigger,
and Vice-named files (sequential clips, sessions, edit temp files) are
never treated as GSR output.
Separately, deleted clip numbers get reused (a new clip can become
Vice_Clip_5 again) and trims rewrite files in place, so the webview
could play a cached older video for the clip it shows. Video URLs are
now versioned by file identity and /v/ responses revalidate (no-cache).