feat(updater): add GitHub releases desktop updater

Adds the GitHub Releases desktop updater with release notes, startup notification, packaging metadata, tests, and CI fixes for Electron E2E.
This commit is contained in:
4gray authored and GitHub committed 2026-06-28 22:21:20 +02:00
1 parent 3cb228d931
commit b1119189e2
54 files changed
+3569 -134

No files matched your search

@@ -123,6 +123,20 @@ export const ELECTRON_BRIDGE_DOWNLOAD_STATUSES = {
export type ElectronBridgeDownloadStatus =
(typeof ELECTRON_BRIDGE_DOWNLOAD_STATUSES)[keyof typeof ELECTRON_BRIDGE_DOWNLOAD_STATUSES];
export const ELECTRON_BRIDGE_APP_UPDATE_STATUSES = {
Unsupported: 'unsupported',
Idle: 'idle',
Checking: 'checking',
Available: 'available',
NotAvailable: 'not-available',
Downloading: 'downloading',
Downloaded: 'downloaded',
Error: 'error',
} as const;
export type ElectronBridgeAppUpdateStatusValue =
(typeof ELECTRON_BRIDGE_APP_UPDATE_STATUSES)[keyof typeof ELECTRON_BRIDGE_APP_UPDATE_STATUSES];
export const ELECTRON_BRIDGE_GLOBAL_RECENTLY_ADDED_KINDS = {
All: 'all',
Series: 'series',
@@ -154,6 +168,49 @@ export interface ElectronBridgeWindowState {
isFullScreen: boolean;
}
export interface ElectronBridgeAppUpdateRelease {
version: string;
releaseDate?: string;
releaseName?: string | null;
releaseNotes?: string | null;
}
export interface ElectronBridgeAppUpdateProgress {
bytesPerSecond?: number;
percent: number;
total?: number;
transferred?: number;
}
export interface ElectronBridgeAppUpdateStatus {
status: ElectronBridgeAppUpdateStatusValue;
currentVersion: string;
latestVersion?: string;
release?: ElectronBridgeAppUpdateRelease;
progress?: ElectronBridgeAppUpdateProgress;
error?: string;
supportedSelfUpdate: boolean;
manualDownloadUrl: string;
}
export type ElectronBridgeAppUpdateReleaseNotesDirection = 'previous' | 'next';
export interface ElectronBridgeAppUpdateReleaseNotesRequest {
version?: string;
direction?: ElectronBridgeAppUpdateReleaseNotesDirection;
}
export interface ElectronBridgeAppUpdateReleaseNotes {
version: string;
tagName: string;
releaseName?: string | null;
publishedAt?: string | null;
bodyMarkdown: string;
htmlUrl: string;
hasPrevious: boolean;
hasNext: boolean;
}
export interface ElectronBridgeAiSettings {
aiProvider: string;
aiModelName: string;
@@ -452,6 +509,16 @@ export interface ElectronBridgeApi {
) => () => void;
getAppVersion: () => Promise<string>;
platform: string;
getAppUpdateStatus: () => Promise<ElectronBridgeAppUpdateStatus>;
checkForAppUpdate: () => Promise<ElectronBridgeAppUpdateStatus>;
downloadAppUpdate: () => Promise<ElectronBridgeAppUpdateStatus>;
installAppUpdate: () => Promise<ElectronBridgeAppUpdateStatus>;
getAppUpdateReleaseNotes: (
request?: ElectronBridgeAppUpdateReleaseNotesRequest
) => Promise<ElectronBridgeAppUpdateReleaseNotes>;
onAppUpdateStatusChange: (
callback: (status: ElectronBridgeAppUpdateStatus) => void
) => () => void;
minimizeWindow: () => Promise<void>;
toggleMaximizeWindow: () => Promise<ElectronBridgeWindowState>;
closeWindow: () => Promise<void>;
@@ -28,6 +28,14 @@ export const VIEW_ADD_PLAYLIST = 'VIEW:PLAYLISTS';
export const AUTO_UPDATE_PLAYLISTS = 'AUTO_UPDATE';
export const AUTO_UPDATE_PLAYLISTS_RESPONSE = 'AUTO_UPDATE_RESPONSE';
// Application updates
export const APP_UPDATE_GET_STATUS = 'APP_UPDATE:GET_STATUS';
export const APP_UPDATE_CHECK = 'APP_UPDATE:CHECK';
export const APP_UPDATE_DOWNLOAD = 'APP_UPDATE:DOWNLOAD';
export const APP_UPDATE_INSTALL = 'APP_UPDATE:INSTALL';
export const APP_UPDATE_GET_RELEASE_NOTES = 'APP_UPDATE:GET_RELEASE_NOTES';
export const APP_UPDATE_STATUS_CHANGED = 'APP_UPDATE:STATUS_CHANGED';
// Experimental
export const OPEN_MPV_PLAYER = 'OPEN_MPV_PLAYER';
export const SET_MPV_PLAYER_PATH = 'SET_MPV_PLAYER_PATH';