Expand wallpaper handling
This commit is contained in:
122
dist/main/system_handlers.js
vendored
122
dist/main/system_handlers.js
vendored
@@ -100,17 +100,119 @@ function registerSystemHandlers() {
|
|||||||
return { success: true };
|
return { success: true };
|
||||||
});
|
});
|
||||||
// 2. Set Wallpaper
|
// 2. Set Wallpaper
|
||||||
electron_1.ipcMain.handle('native:set-wallpaper', async (event, { path: imagePath }) => {
|
// Supports local path OR URL download. URL images are saved to a stable cache dir
|
||||||
const cleanPath = (0, file_utils_1.expandPath)(imagePath);
|
// so macOS can reference them persistently after reboot.
|
||||||
if (!fs.existsSync(cleanPath))
|
// display: 'all' (default) | 'primary' (built-in) | 'external' (projector/second screen)
|
||||||
return { success: false, error: 'Image file not found' };
|
// url_external: optional second URL for the external display only.
|
||||||
if (os.platform() === 'darwin') {
|
electron_1.ipcMain.handle('native:set-wallpaper', async (event, { path: imagePath, url, url_external, display = 'all', api_key, account_id }) => {
|
||||||
const script = `tell application "System Events" to set picture of every desktop to "${cleanPath}"`;
|
// Cache dir: ~/Library/Caches/OSIT/wallpaper on macOS, ~/.cache/osit/wallpaper on Linux.
|
||||||
return await runExec(`osascript -e '${script}'`);
|
// 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') {
|
// HARDENED: write AppleScript to a temp file, same pattern as native:run-osascript.
|
||||||
// Gnome/Ubuntu default
|
// The old osascript -e approach breaks on paths with spaces or special characters.
|
||||||
return await runExec(`gsettings set org.gnome.desktop.background picture-uri "file://${cleanPath}"`);
|
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' };
|
return { success: false, error: 'Platform not supported' };
|
||||||
});
|
});
|
||||||
|
|||||||
2
dist/main/system_handlers.js.map
vendored
2
dist/main/system_handlers.js.map
vendored
File diff suppressed because one or more lines are too long
@@ -48,18 +48,132 @@ export function registerSystemHandlers() {
|
|||||||
});
|
});
|
||||||
|
|
||||||
// 2. Set Wallpaper
|
// 2. Set Wallpaper
|
||||||
ipcMain.handle('native:set-wallpaper', async (event, { path: imagePath }) => {
|
// Supports local path OR URL download. URL images are saved to a stable cache dir
|
||||||
const cleanPath = expandPath(imagePath);
|
// so macOS can reference them persistently after reboot.
|
||||||
if (!fs.existsSync(cleanPath)) return { success: false, error: 'Image file not found' };
|
// 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') {
|
if (os.platform() === 'darwin') {
|
||||||
const script = `tell application "System Events" to set picture of every desktop to "${cleanPath}"`;
|
// Resolve primary image path
|
||||||
return await runExec(`osascript -e '${script}'`);
|
let primary_path: string | null = null;
|
||||||
} else if (os.platform() === 'linux') {
|
|
||||||
// Gnome/Ubuntu default
|
if (imagePath) {
|
||||||
return await runExec(`gsettings set org.gnome.desktop.background picture-uri "file://${cleanPath}"`);
|
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' };
|
return { success: false, error: 'Platform not supported' };
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user