From 1628734dbaa812ea8356cc6df182521270fa08ed Mon Sep 17 00:00:00 2001 From: young Date: Mon, 31 Aug 2026 13:35:57 +1000 Subject: [PATCH] Address review feedback before release --- .github/workflows/release.yml | 19 +++++++++++++- electron/ipc/nativeVideoExport.test.ts | 10 ++++---- electron/ipc/nativeVideoExport.ts | 4 +-- electron/ipc/recording/ffmpeg.ts | 15 +++++------ electron/ipc/register/announcements.ts | 4 +-- .../announcements/AnnouncementDialog.tsx | 25 ++++++++----------- 6 files changed, 46 insertions(+), 31 deletions(-) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index a892dcac..7b49cafd 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -613,6 +613,23 @@ jobs: shopt -s nullglob mkdir -p release-assets/upload + + required_metadata=( + release-assets/windows-x64/latest.yml + release-assets/linux-x64/latest-linux.yml + ) + + if [ "$RELEASE_SCOPE" = "all" ]; then + required_metadata+=(release-assets/macos-merged/latest-mac.yml) + fi + + for file in "${required_metadata[@]}"; do + if [ ! -f "$file" ]; then + echo "Required update metadata is missing: $file" + exit 1 + fi + done + assets=( release-assets/windows-x64/*.exe release-assets/windows-x64/*.blockmap @@ -632,7 +649,7 @@ jobs: fi assets+=( - release-assets/windows-x64/latest*.yml + release-assets/windows-x64/latest.yml release-assets/linux-x64/latest-linux.yml ) diff --git a/electron/ipc/nativeVideoExport.test.ts b/electron/ipc/nativeVideoExport.test.ts index 76585709..47a9a273 100644 --- a/electron/ipc/nativeVideoExport.test.ts +++ b/electron/ipc/nativeVideoExport.test.ts @@ -153,7 +153,7 @@ describe("native static layout command builders", () => { expect(args).toContain("-filter_complex"); expect(args).toContain( "color=c=0x101010:s=1920x1080:r=60:d=60.000,format=nv12,setrange=limited,hwupload_cuda[bg];" + - "[0:v]scale_cuda=w=1536:h=864:format=nv12:passthrough=0,hwdownload,format=nv12,scale=in_range=auto:out_range=tv:sws_dither=a_dither,fps=60,hwupload_cuda[fg];" + + "[0:v]scale_cuda=w=1536:h=864:format=nv12:passthrough=0,hwdownload,format=nv12,scale=in_range=auto:out_range=tv:sws_dither=bayer,fps=60,hwupload_cuda[fg];" + "[bg][fg]overlay_cuda=192:108:shortest=0:repeatlast=1:eof_action=repeat,trim=duration=60.000,setpts=PTS-STARTPTS[out]", ); expect(args).toContain("h264_nvenc"); @@ -179,7 +179,7 @@ describe("native static layout command builders", () => { expect(args).toEqual( expect.arrayContaining([ "-vf", - "vflip,scale=in_range=full:out_range=tv:sws_dither=a_dither", + "vflip,scale=in_range=full:out_range=tv:sws_dither=bayer", "-colorspace", "bt709", "-color_primaries", @@ -198,7 +198,7 @@ describe("native static layout command builders", () => { expect(args).toEqual( expect.arrayContaining([ "-vf", - "scale_cuda=w=1536:h=864:format=nv12:passthrough=0,hwdownload,format=nv12,scale=in_range=auto:out_range=tv:sws_dither=a_dither,fps=60,pad=w=1920:h=1080:x=192:y=108:color=0x101010", + "scale_cuda=w=1536:h=864:format=nv12:passthrough=0,hwdownload,format=nv12,scale=in_range=auto:out_range=tv:sws_dither=bayer,fps=60,pad=w=1920:h=1080:x=192:y=108:color=0x101010", "-map", "0:v:0", "-an", @@ -214,7 +214,7 @@ describe("native static layout command builders", () => { }); expect(args).toContain( - "scale_cuda=w=1536:h=864:format=nv12:passthrough=0,hwdownload,format=nv12,scale=in_range=auto:out_range=tv:sws_dither=a_dither,fps=60,pad=w=1920:h=1080:x=192:y=108:color=0x101010", + "scale_cuda=w=1536:h=864:format=nv12:passthrough=0,hwdownload,format=nv12,scale=in_range=auto:out_range=tv:sws_dither=bayer,fps=60,pad=w=1920:h=1080:x=192:y=108:color=0x101010", ); }); @@ -267,7 +267,7 @@ describe("native static layout command builders", () => { expect(filterComplex).toContain("[fgbase][mask]alphamerge[fg]"); expect(filterComplex).toContain("overlay=x=192:y=108:format=auto"); expect(filterComplex).toContain( - "scale=in_range=full:out_range=tv:sws_dither=a_dither,format=yuv420p[out]", + "scale=in_range=full:out_range=tv:sws_dither=bayer,format=yuv420p[out]", ); expect(args).toContain("h264_nvenc"); expect(args).toEqual(expect.arrayContaining(["-pix_fmt", "yuv420p"])); diff --git a/electron/ipc/nativeVideoExport.ts b/electron/ipc/nativeVideoExport.ts index 7d9e1369..8b9a0fa3 100644 --- a/electron/ipc/nativeVideoExport.ts +++ b/electron/ipc/nativeVideoExport.ts @@ -20,9 +20,9 @@ export const FFMPEG_BT709_VIDEO_COLOR_ARGS = [ "tv", ] as const; -const FFMPEG_AUTO_TO_VIDEO_RANGE_FILTER = "scale=in_range=auto:out_range=tv:sws_dither=a_dither"; +const FFMPEG_AUTO_TO_VIDEO_RANGE_FILTER = "scale=in_range=auto:out_range=tv:sws_dither=bayer"; const FFMPEG_AUTO_TO_FULL_RANGE_FILTER = "scale=in_range=auto:out_range=full"; -const FFMPEG_FULL_TO_VIDEO_RANGE_FILTER = "scale=in_range=full:out_range=tv:sws_dither=a_dither"; +const FFMPEG_FULL_TO_VIDEO_RANGE_FILTER = "scale=in_range=full:out_range=tv:sws_dither=bayer"; export type NativeExportEncodingMode = "fast" | "balanced" | "quality"; diff --git a/electron/ipc/recording/ffmpeg.ts b/electron/ipc/recording/ffmpeg.ts index 0c38eb0b..bc6014c7 100644 --- a/electron/ipc/recording/ffmpeg.ts +++ b/electron/ipc/recording/ffmpeg.ts @@ -23,10 +23,10 @@ export function getDisplayWorkAreaForSource(source: SelectedSource) { } export async function buildFfmpegCaptureArgs(source: SelectedSource, outputPath: string) { - const commonOutputArgs = [ + const buildOutputArgs = (inputRange: "auto" | "full") => [ "-an", "-vf", - "scale=in_range=full:out_range=tv:sws_dither=a_dither", + `scale=in_range=${inputRange}:out_range=tv:sws_dither=bayer`, "-c:v", "libx264", "-preset", @@ -45,6 +45,7 @@ export async function buildFfmpegCaptureArgs(source: SelectedSource, outputPath: "+faststart", outputPath, ]; + const fullRangeOutputArgs = buildOutputArgs("full"); if (process.platform === "win32") { if (source?.id?.startsWith("window:")) { @@ -67,7 +68,7 @@ export async function buildFfmpegCaptureArgs(source: SelectedSource, outputPath: "0", "-i", windowId ? `hwnd=${windowId}` : `title=${windowTitle}`, - ...commonOutputArgs, + ...fullRangeOutputArgs, ]; } @@ -81,7 +82,7 @@ export async function buildFfmpegCaptureArgs(source: SelectedSource, outputPath: "0", "-i", "desktop", - ...commonOutputArgs, + ...fullRangeOutputArgs, ]; } @@ -105,7 +106,7 @@ export async function buildFfmpegCaptureArgs(source: SelectedSource, outputPath: `${Math.max(2, bounds.width)}x${Math.max(2, bounds.height)}`, "-i", `${displayEnv}+${Math.round(bounds.x)},${Math.round(bounds.y)}`, - ...commonOutputArgs, + ...fullRangeOutputArgs, ]; } @@ -122,7 +123,7 @@ export async function buildFfmpegCaptureArgs(source: SelectedSource, outputPath: `${Math.max(2, bounds.width)}x${Math.max(2, bounds.height)}`, "-i", `${displayEnv}+${Math.round(bounds.x)},${Math.round(bounds.y)}`, - ...commonOutputArgs, + ...fullRangeOutputArgs, ]; } @@ -137,7 +138,7 @@ export async function buildFfmpegCaptureArgs(source: SelectedSource, outputPath: "60", "-i", "1:none", - ...commonOutputArgs, + ...buildOutputArgs("auto"), ]; } diff --git a/electron/ipc/register/announcements.ts b/electron/ipc/register/announcements.ts index a582fb4e..c5791e99 100644 --- a/electron/ipc/register/announcements.ts +++ b/electron/ipc/register/announcements.ts @@ -56,13 +56,13 @@ async function requestAnnouncementFeed(feedUrl: string): Promise { } cachedFeed = JSON.parse(text) as unknown; + cachedAt = Date.now(); + hasCachedResult = true; return cachedFeed; } catch (error) { console.warn("Failed to load announcement feed:", error); return cachedFeed; } finally { - cachedAt = Date.now(); - hasCachedResult = true; clearTimeout(timeout); } } diff --git a/src/components/announcements/AnnouncementDialog.tsx b/src/components/announcements/AnnouncementDialog.tsx index 42306edc..2496c6c7 100644 --- a/src/components/announcements/AnnouncementDialog.tsx +++ b/src/components/announcements/AnnouncementDialog.tsx @@ -4,18 +4,18 @@ import { toast } from "sonner"; import { BUNDLED_ANNOUNCEMENT_FEED } from "@/content/announcements"; import { useI18n } from "@/contexts/I18nContext"; import { runAnnouncementAction } from "@/lib/announcementActions"; -import { - type Announcement, - type AnnouncementAudience, - parseAnnouncementFeed, - selectAnnouncements, -} from "@/lib/announcements"; import { dismissAnnouncements, readAnnouncementImpressionCounts, readDismissedAnnouncementIds, recordAnnouncementImpression, } from "@/lib/announcementState"; +import { + type Announcement, + type AnnouncementAudience, + parseAnnouncementFeed, + selectAnnouncements, +} from "@/lib/announcements"; import { cn } from "@/lib/utils"; import { Button } from "../ui/button"; import { Dialog, DialogContent, DialogDescription, DialogHeader, DialogTitle } from "../ui/dialog"; @@ -174,13 +174,6 @@ export function AnnouncementDialog({ audience }: { audience: AnnouncementAudienc setCurrentIndex((index) => Math.min(index, remaining.length - 1)); }; - const dismissAll = () => { - dismissAnnouncements(announcements.map((announcement) => announcement.id)); - setAnnouncements([]); - setCurrentIndex(0); - setOpen(false); - }; - const openAction = async () => { if (!current?.action) { return; @@ -209,7 +202,11 @@ export function AnnouncementDialog({ audience }: { audience: AnnouncementAudienc open={open} onOpenChange={(nextOpen) => { if (!nextOpen) { - dismissAll(); + if (controls.dismiss) { + dismissCurrent(); + } else { + setOpen(false); + } } }} >