Skip to content

Customize download folder location and fix Windows autodetection#27472

Open
julien-wff wants to merge 2 commits intoraycast:mainfrom
julien-wff:ext/immich
Open

Customize download folder location and fix Windows autodetection#27472
julien-wff wants to merge 2 commits intoraycast:mainfrom
julien-wff:ext/immich

Conversation

@julien-wff
Copy link
Copy Markdown
Contributor

Description

Previously, when downloading an asset on Windows, it always went to C:\Users\<user>\Downloads. This caused problems for users that moved their download folder to another location (see #27396)

Now, users can customize their download folder in the preferences.

image

Alternatively, if they don't specify a download folder and they're on Windows, the download folder path detection has been improved, looking for the value in the registry.

On MacOS, default path will still always be ~/Downloads

Screencast

Checklist

@raycastbot raycastbot added extension fix / improvement Label for PRs with extension's fix improvements extension: immich Issues related to the immich extension platform: macOS platform: Windows OP is contributor The OP of the PR is a contributor of the extension labels Apr 27, 2026
@raycastbot
Copy link
Copy Markdown
Collaborator

Thank you for your contribution! 🎉

🔔 @xmok you might want to have a look.

You can use this guide to learn how to check out the Pull Request locally in order to test it.

📋 Quick checkout commands
BRANCH="ext/immich"
FORK_URL="https://github.com/julien-wff/raycast-ext-immich.git"
EXTENSION_NAME="immich"
REPO_NAME="raycast-ext-immich"

git clone -n --depth=1 --filter=tree:0 -b $BRANCH $FORK_URL
cd $REPO_NAME
git sparse-checkout set --no-cone "extensions/$EXTENSION_NAME"
git checkout
cd "extensions/$EXTENSION_NAME"
npm install && npm run dev

We're currently experiencing a high volume of incoming requests. As a result, the initial review may take up to 10-15 business days.

@greptile-apps
Copy link
Copy Markdown
Contributor

greptile-apps Bot commented Apr 27, 2026

Greptile Summary

This PR adds a user-configurable download_folder preference and improves Windows download-folder auto-detection by reading from the registry via runPowerShellScript. The approach is sound, but there is a P1 bug in the registry lookup: runPowerShellScript returns raw stdout with a trailing , so the untrimmed path is passed to existsSync, which always returns false, causing the registry result to be ignored and "" to be permanently cached — leaving Windows users back on ~/Downloads.

Confidence Score: 3/5

Not safe to merge as-is — the core Windows registry detection is silently broken due to an untrimmed PowerShell output string.

A single P1 bug directly undermines the main goal of the PR (fixing Windows download folder detection); the fix is a one-line .trim() call, but without it the feature doesn't work at all on Windows.

extensions/immich/src/utils/download.ts — specifically the windowsGetDownloadFolder function and its cache logic.

Important Files Changed

Filename Overview
extensions/immich/src/utils/download.ts Adds Windows registry lookup and user preference for download folder; has a P1 bug where runPowerShellScript output isn't trimmed, causing existsSync to always fail and defeating the registry detection logic.
extensions/immich/package.json Adds a directory-type optional download_folder preference; dependency on @raycast/utils was already present.
extensions/immich/CHANGELOG.md New changelog entry correctly placed at the top with {PR_MERGE_DATE} placeholder.
Prompt To Fix All With AI
This is a comment left during a code review.
Path: extensions/immich/src/utils/download.ts
Line: 23-32

Comment:
**`runPowerShellScript` output not trimmed — `existsSync` will always return false**

`runPowerShellScript` returns raw stdout, which includes a trailing newline (`\r\n` on Windows). Passing that untrimmed string to `existsSync` means the path will never match a real filesystem entry, so the condition on line 28 always fails, `""` gets cached permanently, and Windows users always fall back to `~/Downloads` — exactly the bug this PR intends to fix.

```suggestion
  const rawPath = await runPowerShellScript(
    `(Get-ItemProperty -Path "${WINDOWS_REG_DOWNLOAD_KEY}")."${WINDOWS_REG_DOWNLOAD_VALUE}"`,
    { timeout: 2000 },
  ).catch(() => null);

  const path = rawPath?.trim() || null;

  if (path && existsSync(path)) {
```

How can I resolve this? If you propose a fix, please make it concise.

---

This is a comment left during a code review.
Path: extensions/immich/src/utils/download.ts
Line: 18-36

Comment:
**Permanent cache prevents recovery from transient failures**

When the registry read fails (timeout, PowerShell unavailable, etc.) or the path doesn't exist, `""` is stored in the cache indefinitely. On subsequent calls `cache.has("download_folder")` is `true`, so the registry is never queried again and the user is silently stuck with `~/Downloads` for the lifetime of the cache. Similarly, if the user later moves their Downloads folder, the previously-cached registry path becomes stale and cannot self-correct.

Consider either not caching failure states (omit the `cache.set("download_folder", "")` line), or using a short TTL if the `Cache` API supports it.

How can I resolve this? If you propose a fix, please make it concise.

Reviews (1): Last reviewed commit: "chores: add changelogs for v2" | Re-trigger Greptile

Comment on lines +23 to +32
const path = await runPowerShellScript(
`(Get-ItemProperty -Path "${WINDOWS_REG_DOWNLOAD_KEY}")."${WINDOWS_REG_DOWNLOAD_VALUE}"`,
{ timeout: 2000 },
).catch(() => null);

if (path && existsSync(path)) {
const realPath = await realpath(path);
cache.set("download_folder", realPath);
return realPath;
}
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 runPowerShellScript output not trimmed — existsSync will always return false

runPowerShellScript returns raw stdout, which includes a trailing newline (\r\n on Windows). Passing that untrimmed string to existsSync means the path will never match a real filesystem entry, so the condition on line 28 always fails, "" gets cached permanently, and Windows users always fall back to ~/Downloads — exactly the bug this PR intends to fix.

Suggested change
const path = await runPowerShellScript(
`(Get-ItemProperty -Path "${WINDOWS_REG_DOWNLOAD_KEY}")."${WINDOWS_REG_DOWNLOAD_VALUE}"`,
{ timeout: 2000 },
).catch(() => null);
if (path && existsSync(path)) {
const realPath = await realpath(path);
cache.set("download_folder", realPath);
return realPath;
}
const rawPath = await runPowerShellScript(
`(Get-ItemProperty -Path "${WINDOWS_REG_DOWNLOAD_KEY}")."${WINDOWS_REG_DOWNLOAD_VALUE}"`,
{ timeout: 2000 },
).catch(() => null);
const path = rawPath?.trim() || null;
if (path && existsSync(path)) {
Prompt To Fix With AI
This is a comment left during a code review.
Path: extensions/immich/src/utils/download.ts
Line: 23-32

Comment:
**`runPowerShellScript` output not trimmed — `existsSync` will always return false**

`runPowerShellScript` returns raw stdout, which includes a trailing newline (`\r\n` on Windows). Passing that untrimmed string to `existsSync` means the path will never match a real filesystem entry, so the condition on line 28 always fails, `""` gets cached permanently, and Windows users always fall back to `~/Downloads` — exactly the bug this PR intends to fix.

```suggestion
  const rawPath = await runPowerShellScript(
    `(Get-ItemProperty -Path "${WINDOWS_REG_DOWNLOAD_KEY}")."${WINDOWS_REG_DOWNLOAD_VALUE}"`,
    { timeout: 2000 },
  ).catch(() => null);

  const path = rawPath?.trim() || null;

  if (path && existsSync(path)) {
```

How can I resolve this? If you propose a fix, please make it concise.

Comment on lines +18 to +36
async function windowsGetDownloadFolder() {
if (cache.has("download_folder")) {
return cache.get("download_folder") || null;
}

const path = await runPowerShellScript(
`(Get-ItemProperty -Path "${WINDOWS_REG_DOWNLOAD_KEY}")."${WINDOWS_REG_DOWNLOAD_VALUE}"`,
{ timeout: 2000 },
).catch(() => null);

if (path && existsSync(path)) {
const realPath = await realpath(path);
cache.set("download_folder", realPath);
return realPath;
}

cache.set("download_folder", "");
return null;
}
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Permanent cache prevents recovery from transient failures

When the registry read fails (timeout, PowerShell unavailable, etc.) or the path doesn't exist, "" is stored in the cache indefinitely. On subsequent calls cache.has("download_folder") is true, so the registry is never queried again and the user is silently stuck with ~/Downloads for the lifetime of the cache. Similarly, if the user later moves their Downloads folder, the previously-cached registry path becomes stale and cannot self-correct.

Consider either not caching failure states (omit the cache.set("download_folder", "") line), or using a short TTL if the Cache API supports it.

Prompt To Fix With AI
This is a comment left during a code review.
Path: extensions/immich/src/utils/download.ts
Line: 18-36

Comment:
**Permanent cache prevents recovery from transient failures**

When the registry read fails (timeout, PowerShell unavailable, etc.) or the path doesn't exist, `""` is stored in the cache indefinitely. On subsequent calls `cache.has("download_folder")` is `true`, so the registry is never queried again and the user is silently stuck with `~/Downloads` for the lifetime of the cache. Similarly, if the user later moves their Downloads folder, the previously-cached registry path becomes stale and cannot self-correct.

Consider either not caching failure states (omit the `cache.set("download_folder", "")` line), or using a short TTL if the `Cache` API supports it.

How can I resolve this? If you propose a fix, please make it concise.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

extension fix / improvement Label for PRs with extension's fix improvements extension: immich Issues related to the immich extension OP is contributor The OP of the PR is a contributor of the extension platform: macOS platform: Windows

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants