From 45a7a889a2dd19cdcd82128ff1f020ce6f2e1882 Mon Sep 17 00:00:00 2001
From: BurntToasters <61037367+BurntToasters@users.noreply.github.com>
Date: Sat, 13 Jun 2026 22:08:03 -0700
Subject: [PATCH 1/7] b1
---
CHANGELOG.md | 17 +--
src/main/downloader.ts | 10 +-
src/main/platform.ts | 132 +++++++++++++++++------
src/tests/platform.bundledFfmpeg.test.ts | 14 ++-
src/tests/platform.env.test.ts | 45 ++++----
5 files changed, 151 insertions(+), 67 deletions(-)
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 7827e96..5c04051 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,14 +1,13 @@
-
+> 🅱️ This is a Beta build.
# ⬇️ Downloads
-|
Windows |
macOS |
Linux |
-| :--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | :-------------------------------------------------------------------------------------------------------------- | :----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
-| **EXE:** [x64](https://github.com/BurntToasters/ROSI/releases/download/v4.1.2/ROSI-Windows-x64.exe) / [arm64](https://github.com/BurntToasters/ROSI/releases/download/v4.1.2/ROSI-Windows-arm64.exe) | **[Universal DMG](https://github.com/BurntToasters/ROSI/releases/download/v4.1.2/ROSI-MacOS-universal.dmg)** | **AppImage:** [x64](https://github.com/BurntToasters/ROSI/releases/download/v4.1.2/ROSI-Linux-x86_64.AppImage) / [arm64](https://github.com/BurntToasters/ROSI/releases/download/v4.1.2/ROSI-Linux-arm64.AppImage) |
-|

| **[Universal ZIP](https://github.com/BurntToasters/ROSI/releases/download/v4.1.2/ROSI-MacOS-universal.zip)** | **DEB:** [x64](https://github.com/BurntToasters/ROSI/releases/download/v4.1.2/ROSI-Linux-amd64.deb) / [arm64](https://github.com/BurntToasters/ROSI/releases/download/v4.1.2/ROSI-Linux-arm64.deb) |
-| | | **RPM:** [x64](https://github.com/BurntToasters/ROSI/releases/download/v4.1.2/ROSI-Linux-x86_64.rpm) / [arm64](https://github.com/BurntToasters/ROSI/releases/download/v4.1.2/ROSI-Linux-aarch64.rpm) |
+|
Windows |
macOS |
Linux |
+| :----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | :------------------------------------------------------------------------------------------------------------------ | :------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
+| **EXE:** [x64](https://github.com/BurntToasters/ROSI/releases/download/v4.1.3-beta.1/ROSI-Windows-x64.exe) / [arm64](https://github.com/BurntToasters/ROSI/releases/download/v4.1.3-beta.1/ROSI-Windows-arm64.exe) | **[Universal DMG](https://github.com/BurntToasters/ROSI/releases/download/v4.1.3-beta.1/ROSI-MacOS-universal.dmg)** | **AppImage:** [x64](https://github.com/BurntToasters/ROSI/releases/download/v4.1.3-beta.1/ROSI-Linux-x86_64.AppImage) / [arm64](https://github.com/BurntToasters/ROSI/releases/download/v4.1.3-beta.1/ROSI-Linux-arm64.AppImage) |
+| 
| **[Universal ZIP](https://github.com/BurntToasters/ROSI/releases/download/v4.1.3-beta.1/ROSI-MacOS-universal.zip)** | **DEB:** [x64](https://github.com/BurntToasters/ROSI/releases/download/v4.1.3-beta.1/ROSI-Linux-amd64.deb) / [arm64](https://github.com/BurntToasters/ROSI/releases/download/v4.1.3-beta.1/ROSI-Linux-arm64.deb) |
+| | | **RPM:** [x64](https://github.com/BurntToasters/ROSI/releases/download/v4.1.3-beta.1/ROSI-Linux-x86_64.rpm) / [arm64](https://github.com/BurntToasters/ROSI/releases/download/v4.1.3-beta.1/ROSI-Linux-aarch64.rpm) |
> [!IMPORTANT]
> The `.sig` files in this repo are NOT normal GPG signatures — they are for ROSI's built-in updater to verify the integrity of updates before downloading and installing.
@@ -30,6 +29,10 @@
---
+## Changes in `v4.1.3-beta.1:`
+
+- **FFMPEG:** Ensure bundled ffprobe is executable and always pass the bundled helper directory to yt-dlp so metadata extraction can find it.
+
## Changes in `v4.1.2:`
- **macOS:** Addressed a codesigning issue with yt-dlp/ffmpeg on macOS builds of ROSI.
diff --git a/src/main/downloader.ts b/src/main/downloader.ts
index fb33807..8dee011 100644
--- a/src/main/downloader.ts
+++ b/src/main/downloader.ts
@@ -3,7 +3,13 @@ import * as fs from 'fs';
import sanitize from 'sanitize-filename';
import { dialog } from 'electron';
import log from 'electron-log/main.js';
-import { spawnWithEnv, getEffectiveFfmpegPath, ytdlpBinary, isWindows } from './platform';
+import {
+ spawnWithEnv,
+ getEffectiveFfmpegPath,
+ resolveFfmpegLocationForYtdlp,
+ ytdlpBinary,
+ isWindows,
+} from './platform';
import { killChildProcess } from './processKill';
import { loadSettings, recordDownload } from './settings';
import {
@@ -471,7 +477,7 @@ export function startDownload(
const settings = loadSettings();
const effectiveSettings: Settings = { ...settings };
const ffmpegCommand = getEffectiveFfmpegPath(options.ffmpegPath || settings.ffmpegPath);
- const ffmpegLocation = ffmpegCommand !== 'ffmpeg' ? path.dirname(ffmpegCommand) : null;
+ const ffmpegLocation = resolveFfmpegLocationForYtdlp(options.ffmpegPath || settings.ffmpegPath);
if (options.convertFormat !== undefined) {
if (typeof options.convertFormat === 'string' && options.convertFormat.trim() !== '') {
diff --git a/src/main/platform.ts b/src/main/platform.ts
index 4028a45..931bc37 100644
--- a/src/main/platform.ts
+++ b/src/main/platform.ts
@@ -142,6 +142,42 @@ export function resolveFfmpegPath(customPath: unknown): string | null {
return candidate;
}
+function copyHelperBinaryToTemp(sourcePath: string): string {
+ const binaryName = path.basename(sourcePath);
+ const isFlatpak = Boolean(process.env.FLATPAK_ID);
+ const binDir = isFlatpak
+ ? path.join(app.getPath('userData'), '.bin')
+ : path.join(app.getPath('temp'), 'rosi-bin');
+ if (!fs.existsSync(binDir)) fs.mkdirSync(binDir, { recursive: true });
+ const tmpBin = path.join(binDir, binaryName);
+ fs.copyFileSync(sourcePath, tmpBin);
+ fs.chmodSync(tmpBin, 0o755);
+
+ const probeName = isWindows ? 'ffprobe.exe' : 'ffprobe';
+ const probeSrc = path.join(path.dirname(sourcePath), probeName);
+ if (fs.existsSync(probeSrc)) {
+ const tmpProbe = path.join(binDir, probeName);
+ fs.copyFileSync(probeSrc, tmpProbe);
+ fs.chmodSync(tmpProbe, 0o755);
+ }
+
+ return tmpBin;
+}
+
+function ensureFfmpegHelperBinaries(dir: string): string | null {
+ const ext = isWindows ? '.exe' : '';
+ const ffmpegPath = path.join(dir, `ffmpeg${ext}`);
+ const ffprobePath = path.join(dir, `ffprobe${ext}`);
+ let effectiveFfmpeg: string | null = null;
+ if (fs.existsSync(ffmpegPath)) {
+ effectiveFfmpeg = ensureExecutable(ffmpegPath);
+ }
+ if (fs.existsSync(ffprobePath)) {
+ ensureExecutable(ffprobePath);
+ }
+ return effectiveFfmpeg;
+}
+
function ensureExecutable(filePath: string): string {
if (isWindows) return filePath;
@@ -159,16 +195,7 @@ function ensureExecutable(filePath: string): string {
fs.accessSync(filePath, fs.constants.X_OK);
} catch {
try {
- const binaryName = path.basename(filePath);
- const isFlatpak = Boolean(process.env.FLATPAK_ID);
- const binDir = isFlatpak
- ? path.join(app.getPath('userData'), '.bin')
- : path.join(app.getPath('temp'), 'rosi-bin');
- if (!fs.existsSync(binDir)) fs.mkdirSync(binDir, { recursive: true });
- const tmpBin = path.join(binDir, binaryName);
- fs.copyFileSync(filePath, tmpBin);
- fs.chmodSync(tmpBin, 0o755);
- return tmpBin;
+ return copyHelperBinaryToTemp(filePath);
} catch (copyErr) {
log.error(
`Failed to copy ffmpeg to temp for execution: ${(copyErr as Error).message}`
@@ -218,10 +245,12 @@ export function resolveBundledFfmpegPath(): string | null {
const ext = isWindows ? '.exe' : '';
const bundledPath = path.join(bundledDir, `ffmpeg${ext}`);
if (fs.existsSync(bundledPath)) {
- const effectivePath = ensureExecutable(bundledPath);
- cachedBundledFfmpegPath = effectivePath;
- log.info(`Resolved bundled ffmpeg at: ${effectivePath}`);
- return effectivePath;
+ const effectivePath = ensureFfmpegHelperBinaries(bundledDir);
+ if (effectivePath) {
+ cachedBundledFfmpegPath = effectivePath;
+ log.info(`Resolved bundled ffmpeg at: ${effectivePath}`);
+ return effectivePath;
+ }
}
}
@@ -256,36 +285,69 @@ export function getEffectiveFfmpegPath(customPath?: string | null): string {
return 'ffmpeg';
}
+export function resolveFfmpegLocationForYtdlp(customPath?: string | null): string | null {
+ const resolved = resolveFfmpegPath(customPath);
+ if (resolved) {
+ const dir = path.dirname(resolved);
+ ensureFfmpegHelperBinaries(dir);
+ return dir;
+ }
+
+ const bundledDir = getBundledFfmpegDir();
+ if (!bundledDir) return null;
+
+ const ext = isWindows ? '.exe' : '';
+ if (!fs.existsSync(path.join(bundledDir, `ffmpeg${ext}`))) return null;
+
+ ensureFfmpegHelperBinaries(bundledDir);
+ return bundledDir;
+}
+
export function hasBundledFfmpeg(): boolean {
return resolveBundledFfmpegPath() !== null;
}
export function verifyBundledFfmpeg(): void {
- const ffmpegPath = resolveBundledFfmpegPath();
- if (!ffmpegPath) {
+ const bundledDir = getBundledFfmpegDir();
+ if (!bundledDir) {
log.info('No bundled ffmpeg found; will rely on system ffmpeg.');
return;
}
- try {
- const proc = spawnWithEnv(ffmpegPath, ['-version'], { shell: false });
- let output = '';
- proc.stdout?.on('data', (data: Buffer) => {
- if (output.length < 512) output += data.toString();
- });
- proc.on('close', (code: number | null) => {
- if (code === 0 && output) {
- const firstLine = output.split('\n')[0]?.trim() ?? '';
- log.info(`Bundled ffmpeg verified: ${firstLine}`);
- } else {
- log.warn(`Bundled ffmpeg at ${ffmpegPath} exited with code ${code}`);
- }
- });
- proc.on('error', (err: Error) => {
- log.warn(`Bundled ffmpeg at ${ffmpegPath} failed to execute: ${err.message}`);
- });
- } catch (err) {
- log.warn(`Failed to verify bundled ffmpeg: ${(err as Error).message}`);
+ ensureFfmpegHelperBinaries(bundledDir);
+
+ const ext = isWindows ? '.exe' : '';
+ const helpers = [
+ { label: 'ffmpeg', filePath: path.join(bundledDir, `ffmpeg${ext}`) },
+ { label: 'ffprobe', filePath: path.join(bundledDir, `ffprobe${ext}`) },
+ ];
+
+ for (const helper of helpers) {
+ if (!fs.existsSync(helper.filePath)) {
+ log.warn(`Bundled ${helper.label} not found at ${helper.filePath}`);
+ continue;
+ }
+
+ try {
+ const proc = spawnWithEnv(helper.filePath, ['-version'], { shell: false });
+ let output = '';
+ proc.stdout?.on('data', (data: Buffer) => {
+ if (output.length < 512) output += data.toString();
+ });
+ proc.on('close', (code: number | null) => {
+ if (code === 0 && output) {
+ const firstLine = output.split('\n')[0]?.trim() ?? '';
+ log.info(`Bundled ${helper.label} verified: ${firstLine}`);
+ } else {
+ log.warn(`Bundled ${helper.label} at ${helper.filePath} exited with code ${code}`);
+ }
+ });
+ proc.on('error', (err: Error) => {
+ log.warn(`Bundled ${helper.label} at ${helper.filePath} failed to execute: ${err.message}`);
+ });
+ } catch (err) {
+ log.warn(`Failed to verify bundled ${helper.label}: ${(err as Error).message}`);
+ }
}
}
diff --git a/src/tests/platform.bundledFfmpeg.test.ts b/src/tests/platform.bundledFfmpeg.test.ts
index a8c687e..c8b71b8 100644
--- a/src/tests/platform.bundledFfmpeg.test.ts
+++ b/src/tests/platform.bundledFfmpeg.test.ts
@@ -85,11 +85,23 @@ describe('platform bundled ffmpeg resolution', () => {
expect(platform.getEffectiveFfmpegPath('')).toBe(expectedPath);
});
- it('falls back to system ffmpeg when no bundled or custom path is available', async () => {
+ it('resolveFfmpegLocationForYtdlp returns bundled directory for yt-dlp', async () => {
+ const resourcesPath = createTempResourcesPath();
+ const ffmpegName = process.platform === 'win32' ? 'ffmpeg.exe' : 'ffmpeg';
+ const ffprobeName = process.platform === 'win32' ? 'ffprobe.exe' : 'ffprobe';
+ createBinary(resourcesPath, path.join('ffmpeg', ffmpegName));
+ createBinary(resourcesPath, path.join('ffmpeg', ffprobeName));
+ const platform = await loadPlatformModule(resourcesPath);
+
+ expect(platform.resolveFfmpegLocationForYtdlp('')).toBe(path.join(resourcesPath, 'ffmpeg'));
+ });
+
+ it('resolveFfmpegLocationForYtdlp returns null when no bundled or custom path exists', async () => {
const resourcesPath = createTempResourcesPath();
fs.mkdirSync(path.join(resourcesPath, 'ffmpeg'), { recursive: true });
const platform = await loadPlatformModule(resourcesPath);
+ expect(platform.resolveFfmpegLocationForYtdlp('')).toBeNull();
expect(platform.resolveBundledFfmpegPath()).toBeNull();
expect(platform.hasBundledFfmpeg()).toBe(false);
expect(platform.getEffectiveFfmpegPath('')).toBe('ffmpeg');
diff --git a/src/tests/platform.env.test.ts b/src/tests/platform.env.test.ts
index 9ec3e3c..c6ba81e 100644
--- a/src/tests/platform.env.test.ts
+++ b/src/tests/platform.env.test.ts
@@ -6,6 +6,15 @@ const initialResourcesPath = (process as NodeJS.Process & { resourcesPath?: stri
const initialPlatform = process.platform;
const initialArch = process.arch;
const ffmpegBinaryName = process.platform === 'win32' ? 'ffmpeg.exe' : 'ffmpeg';
+const ffprobeBinaryName = process.platform === 'win32' ? 'ffprobe.exe' : 'ffprobe';
+
+function bundledHelperExists(target: string): boolean {
+ const normalized = target.replace(/\\/g, '/');
+ return (
+ normalized.endsWith(`/ffmpeg/${ffmpegBinaryName}`) ||
+ normalized.endsWith(`/ffmpeg/${ffprobeBinaryName}`)
+ );
+}
interface PlatformEnvMocks {
existsSyncMock: ReturnType;
@@ -204,33 +213,34 @@ describe('platform env and ffmpeg verification', () => {
it('verifyBundledFfmpeg logs first version line on success', async () => {
const proc = createProc();
const { mod, mocks } = await loadPlatform((m) => {
- m.existsSyncMock.mockImplementation((target: string) =>
- target.replace(/\\/g, '/').endsWith(`/ffmpeg/${ffmpegBinaryName}`)
- );
+ m.existsSyncMock.mockImplementation((target: string) => bundledHelperExists(target));
m.spawnMock.mockReturnValue(proc);
});
mod.verifyBundledFfmpeg();
proc.stdout.emit('data', Buffer.from('ffmpeg version 7.1\nmore'));
proc.emit('close', 0);
+ proc.stdout.emit('data', Buffer.from('ffprobe version 7.1\nmore'));
+ proc.emit('close', 0);
expect(mocks.logInfoMock).toHaveBeenCalledWith(
expect.stringContaining('Bundled ffmpeg verified: ffmpeg version 7.1')
);
+ expect(mocks.spawnMock).toHaveBeenCalledTimes(2);
});
it('verifyBundledFfmpeg logs non-zero close and process errors', async () => {
const proc = createProc();
const { mod, mocks } = await loadPlatform((m) => {
- m.existsSyncMock.mockImplementation((target: string) =>
- target.replace(/\\/g, '/').endsWith(`/ffmpeg/${ffmpegBinaryName}`)
- );
+ m.existsSyncMock.mockImplementation((target: string) => bundledHelperExists(target));
m.spawnMock.mockReturnValue(proc);
});
mod.verifyBundledFfmpeg();
proc.emit('close', 2);
proc.emit('error', new Error('blocked'));
+ proc.emit('close', 2);
+ proc.emit('error', new Error('blocked'));
expect(mocks.logWarnMock).toHaveBeenCalledWith(expect.stringContaining('exited with code 2'));
expect(mocks.logWarnMock).toHaveBeenCalledWith(
@@ -240,9 +250,7 @@ describe('platform env and ffmpeg verification', () => {
it('verifyBundledFfmpeg catches spawn exceptions', async () => {
const { mod, mocks } = await loadPlatform((m) => {
- m.existsSyncMock.mockImplementation((target: string) =>
- target.replace(/\\/g, '/').endsWith(`/ffmpeg/${ffmpegBinaryName}`)
- );
+ m.existsSyncMock.mockImplementation((target: string) => bundledHelperExists(target));
m.spawnMock.mockImplementation(() => {
throw new Error('spawn blocked');
});
@@ -298,9 +306,7 @@ describe('platform env and ffmpeg verification', () => {
it('chmods bundled ffmpeg on Linux when not executable', async () => {
const { mod, mocks } = await loadPlatform((m) => {
- m.existsSyncMock.mockImplementation((target: string) =>
- target.replace(/\\/g, '/').endsWith('/ffmpeg/ffmpeg')
- );
+ m.existsSyncMock.mockImplementation((target: string) => bundledHelperExists(target));
m.statSyncMock.mockReturnValue({ isDirectory: () => false, mode: 0o644 });
}, 'linux');
@@ -308,14 +314,12 @@ describe('platform env and ffmpeg verification', () => {
expect(resolved?.replace(/\\/g, '/')).toBe('/app/resources/ffmpeg/ffmpeg');
expect(mocks.chmodSyncMock).toHaveBeenCalledWith(expect.stringContaining('ffmpeg'), 0o755);
+ expect(mocks.chmodSyncMock).toHaveBeenCalledWith(expect.stringContaining('ffprobe'), 0o755);
});
it('copies bundled ffmpeg to temp bin when chmod and access fail on Linux', async () => {
const { mod, mocks } = await loadPlatform((m) => {
- m.existsSyncMock.mockImplementation((target: string) => {
- const normalized = target.replace(/\\/g, '/');
- return normalized.endsWith('/ffmpeg/ffmpeg');
- });
+ m.existsSyncMock.mockImplementation((target: string) => bundledHelperExists(target));
m.statSyncMock.mockReturnValue({ isDirectory: () => false, mode: 0o644 });
m.chmodSyncMock.mockImplementationOnce(() => {
const err = new Error('readonly') as NodeJS.ErrnoException;
@@ -333,17 +337,14 @@ describe('platform env and ffmpeg verification', () => {
expect(mocks.mkdirSyncMock).toHaveBeenCalledWith(expect.stringContaining('rosi-bin'), {
recursive: true,
});
- expect(mocks.copyFileSyncMock).toHaveBeenCalled();
- expect(mocks.chmodSyncMock).toHaveBeenLastCalledWith(expect.stringContaining('ffmpeg'), 0o755);
+ expect(mocks.copyFileSyncMock).toHaveBeenCalledTimes(2);
+ expect(mocks.chmodSyncMock).toHaveBeenCalledWith(expect.stringContaining('ffprobe'), 0o755);
});
it('copies bundled ffmpeg to app data bin inside Flatpak', async () => {
vi.stubEnv('FLATPAK_ID', 'com.burnttoasters.rosi');
const { mod, mocks } = await loadPlatform((m) => {
- m.existsSyncMock.mockImplementation((target: string) => {
- const normalized = target.replace(/\\/g, '/');
- return normalized.endsWith('/ffmpeg/ffmpeg');
- });
+ m.existsSyncMock.mockImplementation((target: string) => bundledHelperExists(target));
m.statSyncMock.mockReturnValue({ isDirectory: () => false, mode: 0o644 });
m.chmodSyncMock.mockImplementationOnce(() => {
const err = new Error('readonly') as NodeJS.ErrnoException;
From 7b9cf4a5bab445fc06ea3fe397b69c28a3268413 Mon Sep 17 00:00:00 2001
From: BurntToasters <61037367+BurntToasters@users.noreply.github.com>
Date: Sat, 13 Jun 2026 22:09:58 -0700
Subject: [PATCH 2/7] b1
---
com.burnttoasters.rosi.metainfo.xml | 2 +-
package-lock.json | 12 ++++++------
package.json | 2 +-
src/renderer/splash.html | 2 +-
src/tests/downloader.errorPaths.test.ts | 3 +++
src/tests/downloader.fetchFormats.test.ts | 1 +
src/tests/downloader.session.test.ts | 1 +
7 files changed, 14 insertions(+), 9 deletions(-)
diff --git a/com.burnttoasters.rosi.metainfo.xml b/com.burnttoasters.rosi.metainfo.xml
index 898c94e..ad5187e 100644
--- a/com.burnttoasters.rosi.metainfo.xml
+++ b/com.burnttoasters.rosi.metainfo.xml
@@ -33,7 +33,7 @@
-
+
diff --git a/package-lock.json b/package-lock.json
index 2778ef0..3591efd 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -1,12 +1,12 @@
{
"name": "rosi",
- "version": "4.1.2",
+ "version": "4.1.3-beta.1",
"lockfileVersion": 3,
"requires": true,
"packages": {
"": {
"name": "rosi",
- "version": "4.1.2",
+ "version": "4.1.3-beta.1",
"license": "MPL-2.0",
"dependencies": {
"electron-log": "^5.3.4",
@@ -954,14 +954,14 @@
}
},
"node_modules/@napi-rs/wasm-runtime": {
- "version": "1.1.4",
- "resolved": "https://registry.npmjs.org/@napi-rs/wasm-runtime/-/wasm-runtime-1.1.4.tgz",
- "integrity": "sha512-3NQNNgA1YSlJb/kMH1ildASP9HW7/7kYnRI2szWJaofaS1hWmbGI4H+d3+22aGzXXN9IJ+n+GiFVcGipJP18ow==",
+ "version": "1.1.5",
+ "resolved": "https://registry.npmjs.org/@napi-rs/wasm-runtime/-/wasm-runtime-1.1.5.tgz",
+ "integrity": "sha512-AWPoBRJ9tsnVhor4sjO7rkni+7p+2IAEFj6cx06UgP10jkQHqay/36uRV/bFkgrh18D9vb4cr8Q0Pthskgzy+Q==",
"dev": true,
"license": "MIT",
"optional": true,
"dependencies": {
- "@tybys/wasm-util": "^0.10.1"
+ "@tybys/wasm-util": "^0.10.2"
},
"funding": {
"type": "github",
diff --git a/package.json b/package.json
index 93cd983..6ce0448 100644
--- a/package.json
+++ b/package.json
@@ -1,6 +1,6 @@
{
"name": "rosi",
- "version": "4.1.2",
+ "version": "4.1.3-beta.1",
"private": true,
"description": "Electron GUI for yt-dlp",
"desktopName": "com.burnttoasters.rosi.desktop",
diff --git a/src/renderer/splash.html b/src/renderer/splash.html
index b331a85..24c2df3 100644
--- a/src/renderer/splash.html
+++ b/src/renderer/splash.html
@@ -327,7 +327,7 @@ ROSI
Loading
- v4.1.2
+ v4.1.3-beta.1
+
diff --git a/src/renderer/licenses-iframe.html b/src/renderer/licenses-iframe.html
index 5f5a1e6..7747c0e 100644
--- a/src/renderer/licenses-iframe.html
+++ b/src/renderer/licenses-iframe.html
@@ -4,7 +4,7 @@
ROSI License & 3rd Party Licenses/Credits