Expand wallpaper handling

This commit is contained in:
Scott Idem
2026-05-13 18:08:49 -04:00
parent 53d200f10e
commit bb51771dc7
3 changed files with 236 additions and 20 deletions

View File

@@ -100,17 +100,119 @@ function registerSystemHandlers() {
return { success: true };
});
// 2. Set Wallpaper
electron_1.ipcMain.handle('native:set-wallpaper', async (event, { path: imagePath }) => {
const cleanPath = (0, file_utils_1.expandPath)(imagePath);
if (!fs.existsSync(cleanPath))
return { success: false, error: 'Image file not found' };
if (os.platform() === 'darwin') {
const script = `tell application "System Events" to set picture of every desktop to "${cleanPath}"`;
return await runExec(`osascript -e '${script}'`);
// Supports local path OR URL download. URL images are saved to a stable cache dir
// so macOS can reference them persistently after reboot.
// display: 'all' (default) | 'primary' (built-in) | 'external' (projector/second screen)
// url_external: optional second URL for the external display only.
electron_1.ipcMain.handle('native:set-wallpaper', async (event, { path: imagePath, url, url_external, display = 'all', api_key, account_id }) => {
// Cache dir: ~/Library/Caches/OSIT/wallpaper on macOS, ~/.cache/osit/wallpaper on Linux.
// Using a stable path means macOS keeps the reference across reboots.
const wallpaper_cache_dir = os.platform() === 'darwin'
? path.join(os.homedir(), 'Library', 'Caches', 'OSIT', 'wallpaper')
: path.join(os.homedir(), '.cache', 'osit', 'wallpaper');
async function download_wallpaper_image(image_url, basename) {
if (!fs.existsSync(wallpaper_cache_dir)) {
fs.mkdirSync(wallpaper_cache_dir, { recursive: true });
}
// Infer extension from URL path, fall back to .jpg
let ext = '.jpg';
try {
const url_path = new URL(image_url).pathname;
const inferred = path.extname(url_path).toLowerCase();
if (['.jpg', '.jpeg', '.png', '.webp'].includes(inferred)) {
ext = inferred === '.jpeg' ? '.jpg' : inferred;
}
}
catch { }
const dest_path = path.join(wallpaper_cache_dir, basename + ext);
const headers = {};
if (api_key)
headers['x-aether-api-key'] = api_key;
if (account_id)
headers['x-account-id'] = account_id;
try {
const response = await (0, axios_1.default)({ method: 'get', url: image_url, responseType: 'stream', headers });
const writer = fs.createWriteStream(dest_path);
response.data.pipe(writer);
await new Promise((resolve, reject) => {
writer.on('finish', resolve);
writer.on('error', reject);
});
return { success: true, path: dest_path };
}
catch (e) {
return { success: false, error: `Wallpaper download failed: ${e.message}` };
}
}
else if (os.platform() === 'linux') {
// Gnome/Ubuntu default
return await runExec(`gsettings set org.gnome.desktop.background picture-uri "file://${cleanPath}"`);
// HARDENED: write AppleScript to a temp file, same pattern as native:run-osascript.
// The old osascript -e approach breaks on paths with spaces or special characters.
async function apply_mac_wallpaper(img_path, display_target) {
const escaped = img_path.replace(/\\/g, '\\\\').replace(/"/g, '\\"');
let script;
if (display_target === 'primary') {
script = `tell application "System Events"\n\ttell desktop 1\n\t\tset picture to "${escaped}"\n\tend tell\nend tell`;
}
else if (display_target === 'external') {
script = `tell application "System Events"\n\ttell desktop 2\n\t\tset picture to "${escaped}"\n\tend tell\nend tell`;
}
else {
script = `tell application "System Events"\n\ttell every desktop\n\t\tset picture to "${escaped}"\n\tend tell\nend tell`;
}
const script_path = path.join(os.tmpdir(), `ae_wallpaper_${Date.now()}.scpt`);
fs.writeFileSync(script_path, script, 'utf-8');
try {
return await runExec(`osascript "${script_path}"`);
}
finally {
try {
fs.unlinkSync(script_path);
}
catch { }
}
}
if (os.platform() === 'darwin') {
// Resolve primary image path
let primary_path = null;
if (imagePath) {
const clean = (0, file_utils_1.expandPath)(imagePath);
if (!fs.existsSync(clean))
return { success: false, error: 'Image file not found' };
primary_path = clean;
}
else if (url) {
const result = await download_wallpaper_image(url, 'wallpaper_primary');
if (!result.success || !result.path)
return { success: false, error: result.error };
primary_path = result.path;
}
if (!primary_path)
return { success: false, error: 'No image source provided' };
if (url_external) {
// Different images for each display: set primary display first, then external
const primary_result = await apply_mac_wallpaper(primary_path, 'primary');
if (!primary_result.success)
return primary_result;
const ext_result = await download_wallpaper_image(url_external, 'wallpaper_external');
const ext_path = ext_result.success && ext_result.path ? ext_result.path : primary_path;
return await apply_mac_wallpaper(ext_path, 'external');
}
else {
return await apply_mac_wallpaper(primary_path, display);
}
}
if (os.platform() === 'linux') {
let img_path = imagePath ? (0, file_utils_1.expandPath)(imagePath) : null;
if (!img_path && url) {
const result = await download_wallpaper_image(url, 'wallpaper_primary');
if (!result.success || !result.path)
return { success: false, error: result.error };
img_path = result.path;
}
if (!img_path)
return { success: false, error: 'No image source provided' };
if (!fs.existsSync(img_path))
return { success: false, error: 'Image file not found' };
return await runExec(`gsettings set org.gnome.desktop.background picture-uri "file://${img_path}"`);
}
return { success: false, error: 'Platform not supported' };
});

File diff suppressed because one or more lines are too long

View File

@@ -48,18 +48,132 @@ export function registerSystemHandlers() {
});
// 2. Set Wallpaper
ipcMain.handle('native:set-wallpaper', async (event, { path: imagePath }) => {
const cleanPath = expandPath(imagePath);
if (!fs.existsSync(cleanPath)) return { success: false, error: 'Image file not found' };
// Supports local path OR URL download. URL images are saved to a stable cache dir
// so macOS can reference them persistently after reboot.
// display: 'all' (default) | 'primary' (built-in) | 'external' (projector/second screen)
// url_external: optional second URL for the external display only.
ipcMain.handle('native:set-wallpaper', async (event, {
path: imagePath,
url,
url_external,
display = 'all',
api_key,
account_id
}: {
path?: string;
url?: string;
url_external?: string;
display?: 'all' | 'primary' | 'external';
api_key?: string;
account_id?: string;
}) => {
// Cache dir: ~/Library/Caches/OSIT/wallpaper on macOS, ~/.cache/osit/wallpaper on Linux.
// Using a stable path means macOS keeps the reference across reboots.
const wallpaper_cache_dir = os.platform() === 'darwin'
? path.join(os.homedir(), 'Library', 'Caches', 'OSIT', 'wallpaper')
: path.join(os.homedir(), '.cache', 'osit', 'wallpaper');
async function download_wallpaper_image(image_url: string, basename: string): Promise<{ success: boolean; path?: string; error?: string }> {
if (!fs.existsSync(wallpaper_cache_dir)) {
fs.mkdirSync(wallpaper_cache_dir, { recursive: true });
}
// Infer extension from URL path, fall back to .jpg
let ext = '.jpg';
try {
const url_path = new URL(image_url).pathname;
const inferred = path.extname(url_path).toLowerCase();
if (['.jpg', '.jpeg', '.png', '.webp'].includes(inferred)) {
ext = inferred === '.jpeg' ? '.jpg' : inferred;
}
} catch {}
const dest_path = path.join(wallpaper_cache_dir, basename + ext);
const headers: Record<string, string> = {};
if (api_key) headers['x-aether-api-key'] = api_key;
if (account_id) headers['x-account-id'] = account_id;
try {
const response = await axios({ method: 'get', url: image_url, responseType: 'stream', headers });
const writer = fs.createWriteStream(dest_path);
response.data.pipe(writer);
await new Promise<void>((resolve, reject) => {
writer.on('finish', resolve);
writer.on('error', reject);
});
return { success: true, path: dest_path };
} catch (e: any) {
return { success: false, error: `Wallpaper download failed: ${e.message}` };
}
}
// HARDENED: write AppleScript to a temp file, same pattern as native:run-osascript.
// The old osascript -e approach breaks on paths with spaces or special characters.
async function apply_mac_wallpaper(img_path: string, display_target: 'all' | 'primary' | 'external'): Promise<{ success: boolean; stdout?: string; stderr?: string; error?: string }> {
const escaped = img_path.replace(/\\/g, '\\\\').replace(/"/g, '\\"');
let script: string;
if (display_target === 'primary') {
script = `tell application "System Events"\n\ttell desktop 1\n\t\tset picture to "${escaped}"\n\tend tell\nend tell`;
} else if (display_target === 'external') {
script = `tell application "System Events"\n\ttell desktop 2\n\t\tset picture to "${escaped}"\n\tend tell\nend tell`;
} else {
script = `tell application "System Events"\n\ttell every desktop\n\t\tset picture to "${escaped}"\n\tend tell\nend tell`;
}
const script_path = path.join(os.tmpdir(), `ae_wallpaper_${Date.now()}.scpt`);
fs.writeFileSync(script_path, script, 'utf-8');
try {
return await runExec(`osascript "${script_path}"`);
} finally {
try { fs.unlinkSync(script_path); } catch {}
}
}
if (os.platform() === 'darwin') {
const script = `tell application "System Events" to set picture of every desktop to "${cleanPath}"`;
return await runExec(`osascript -e '${script}'`);
} else if (os.platform() === 'linux') {
// Gnome/Ubuntu default
return await runExec(`gsettings set org.gnome.desktop.background picture-uri "file://${cleanPath}"`);
// Resolve primary image path
let primary_path: string | null = null;
if (imagePath) {
const clean = expandPath(imagePath);
if (!fs.existsSync(clean)) return { success: false, error: 'Image file not found' };
primary_path = clean;
} else if (url) {
const result = await download_wallpaper_image(url, 'wallpaper_primary');
if (!result.success || !result.path) return { success: false, error: result.error };
primary_path = result.path;
}
if (!primary_path) return { success: false, error: 'No image source provided' };
if (url_external) {
// Different images for each display: set primary display first, then external
const primary_result = await apply_mac_wallpaper(primary_path, 'primary');
if (!primary_result.success) return primary_result;
const ext_result = await download_wallpaper_image(url_external, 'wallpaper_external');
const ext_path = ext_result.success && ext_result.path ? ext_result.path : primary_path;
return await apply_mac_wallpaper(ext_path, 'external');
} else {
return await apply_mac_wallpaper(primary_path, display);
}
}
if (os.platform() === 'linux') {
let img_path: string | null = imagePath ? expandPath(imagePath) : null;
if (!img_path && url) {
const result = await download_wallpaper_image(url, 'wallpaper_primary');
if (!result.success || !result.path) return { success: false, error: result.error };
img_path = result.path;
}
if (!img_path) return { success: false, error: 'No image source provided' };
if (!fs.existsSync(img_path)) return { success: false, error: 'Image file not found' };
return await runExec(`gsettings set org.gnome.desktop.background picture-uri "file://${img_path}"`);
}
return { success: false, error: 'Platform not supported' };
});