Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: let user select the directory to save things #680

Open
wants to merge 2 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
27 changes: 12 additions & 15 deletions screenpipe-app-tauri/components/dev-mode-settings.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ import { Command } from "@tauri-apps/plugin-shell";
import { CliCommandDialog } from "./cli-command-dialog";
import { LogFileButton } from "./log-file-button";

const getDebuggingCommands = (os: string | null) => {
const getDebuggingCommands = (os: string | null, dataDir: string) => {
let cliInstructions = "";

if (os === "windows") {
Expand All @@ -62,28 +62,25 @@ const getDebuggingCommands = (os: string | null) => {
# (Replace [YOUR_ARGS] with your chosen arguments)
# Example: screenpipe --fps 1 `;

const dataDir =
os === "windows" ? "%USERPROFILE%\\.screenpipe" : "$HOME/.screenpipe";

const logPath =
os === "windows"
? `%USERPROFILE%\\.screenpipe\\screenpipe.${
os === "windows"
? `${dataDir}\\screenpipe.${
new Date().toISOString().split("T")[0]
}.log`
: `$HOME/.screenpipe/screenpipe.${
}.log`
: `${dataDir}/screenpipe.${
new Date().toISOString().split("T")[0]
}.log`;
}.log`;

const dbPath =
os === "windows"
? "%USERPROFILE%\\.screenpipe\\db.sqlite"
: "$HOME/.screenpipe/db.sqlite";
? `${dataDir}\\db.sqlite`
: `${dataDir}/db.sqlite`;

const baseCommand =
baseInstructions +
dataDir +
(os === "windows"
? "\n\n# We highly recommend adding --ocr-engine windows-native to your command.\n# This will use a very experimental but powerful engine to extract text from your screen instead of the default one.\n# Example: screenpipe --data-dir %USERPROFILE%\\.screenpipe --ocr-engine windows-native\n"
? `\n\n# We highly recommend adding --ocr-engine windows-native to your command.\n# This will use a very experimental but powerful engine to extract text from your screen instead of the default one.\n# Example: screenpipe --data-dir ${dataDir} --ocr-engine windows-native\n`
: "") +
"\n\n# 5. If you've already started Screenpipe, try these debugging commands:\n";

Expand Down Expand Up @@ -122,7 +119,7 @@ const getDebuggingCommands = (os: string | null) => {
}
};

export const DevModeSettings = () => {
export const DevModeSettings = ({ localDataDir }: { localDataDir: string }) => {
const { settings, updateSettings } = useSettings();
const [localSettings, setLocalSettings] = useState(settings);
const handleDevModeToggle = async (checked: boolean) => {
Expand Down Expand Up @@ -300,7 +297,7 @@ export const DevModeSettings = () => {
did you run screenpipe backend? either click start on the right, or
thru CLI 👇
</p>
<CodeBlock language="bash" value={getDebuggingCommands(platform())} />
<CodeBlock language="bash" value={getDebuggingCommands(platform(), localDataDir)} />

<div className="mt-4 text-sm text-gray-500">
<p>or, for more advanced queries:</p>
Expand All @@ -319,7 +316,7 @@ export const DevModeSettings = () => {
<li>Paste into ChatGPT (Cmd+V)</li>
<li>
ask: &quot;give me 10 sqlite query CLI to look up my data. My db
is in $HOME/.screenpipe/db.sqlite&quot;
is in {localDataDir}/db.sqlite&quot;
</li>
</ol>
<p className="mt-2">
Expand Down
12 changes: 4 additions & 8 deletions screenpipe-app-tauri/components/log-file-button.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ import { open } from "@tauri-apps/plugin-shell";
import { readTextFile } from "@tauri-apps/plugin-fs";
import { useCopyToClipboard } from "@/lib/hooks/use-copy-to-clipboard";
import { cn } from "@/lib/utils";
import { useSettings } from "@/lib/hooks/use-settings";

export const LogFileButton = ({
className,
Expand All @@ -23,17 +24,12 @@ export const LogFileButton = ({
}) => {
const { toast } = useToast();
const { copyToClipboard } = useCopyToClipboard({ timeout: 3000 });
const { getDataDir } = useSettings();

const getLogFilePath = async () => {
const homeDirPath = await homeDir();
const dataDir = await getDataDir();
const logFileName = isAppLog ? "screenpipe-app" : "screenpipe";
return platform() === "windows"
? `${homeDirPath}\\.screenpipe\\${logFileName}.${
new Date().toISOString().split("T")[0]
}.log`
: `${homeDirPath}/.screenpipe/${logFileName}.${
new Date().toISOString().split("T")[0]
}.log`;
return `${dataDir}\\${logFileName}.${new Date().toISOString().split("T")[0]}.log`
};

const handleOpenLogFile = async () => {
Expand Down
8 changes: 4 additions & 4 deletions screenpipe-app-tauri/components/pipe-store.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,7 @@ import {
CollapsibleTrigger,
} from "@/components/ui/collapsible";
import { LogFileButton } from "./log-file-button";
import { useSettings } from "@/lib/hooks/use-settings";

export interface Pipe {
enabled: boolean;
Expand Down Expand Up @@ -96,6 +97,7 @@ const PipeDialog: React.FC = () => {
const [selectedPipe, setSelectedPipe] = useState<Pipe | null>(null);
const [pipes, setPipes] = useState<Pipe[]>([]);
const { health } = useHealthCheck();
const { getDataDir } = useSettings();

useEffect(() => {
fetchInstalledPipes();
Expand Down Expand Up @@ -133,7 +135,7 @@ const PipeDialog: React.FC = () => {
if (!health || health?.status === "error") {
return;
}

const dataDir = await getDataDir();
try {
const response = await fetch("http://localhost:3030/pipes/list");

Expand All @@ -143,10 +145,8 @@ const PipeDialog: React.FC = () => {
const data = await response.json();
for (const pipe of data) {
// read the README.md file from disk and set the fullDescription
const home = await homeDir();
const pathToReadme = await join(
home,
".screenpipe",
dataDir,
"pipes",
pipe.id,
"README.md"
Expand Down
59 changes: 58 additions & 1 deletion screenpipe-app-tauri/components/recording-settings.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ import {
Languages,
Mic,
Monitor,
Folder,
AppWindowMac,
X,
} from "lucide-react";
Expand Down Expand Up @@ -67,6 +68,7 @@ import posthog from "posthog-js";
import { trace } from "@opentelemetry/api";
import { initOpenTelemetry } from "@/lib/opentelemetry";
import { Language } from "@/lib/language";
import { open } from '@tauri-apps/plugin-dialog';
import { Command as ShellCommand } from "@tauri-apps/plugin-shell";
import { CliCommandDialog } from "./cli-command-dialog";
import { ToastAction } from "@/components/ui/toast";
Expand All @@ -91,7 +93,7 @@ export function RecordingSettings({
localSettings: Settings;
setLocalSettings: (settings: Settings) => void;
}) {
const { settings, updateSettings } = useSettings();
const { settings, updateSettings, getDataDir } = useSettings();
const [openAudioDevices, setOpenAudioDevices] = React.useState(false);
const [openMonitors, setOpenMonitors] = React.useState(false);
const [openLanguages, setOpenLanguages] = React.useState(false);
Expand Down Expand Up @@ -230,6 +232,7 @@ export function RecordingSettings({
enableBeta: localSettings.enableBeta,
enableFrameCache: localSettings.enableFrameCache,
enableUiMonitoring: localSettings.enableUiMonitoring,
dataDir: localSettings.dataDir,
};
console.log("Settings to update:", settingsToUpdate);
await updateSettings(settingsToUpdate);
Expand Down Expand Up @@ -262,6 +265,7 @@ export function RecordingSettings({
await invoke("spawn_screenpipe");
await new Promise((resolve) => setTimeout(resolve, 2000));

await invoke("update_screenpipe_dir", { dir: localSettings.dataDir });
toast({
title: "settings updated successfully",
description: "screenpipe has been restarted with new settings.",
Expand Down Expand Up @@ -437,6 +441,33 @@ export function RecordingSettings({
}
};

const handleDataDirChange = async () => {
try {
const dataDir = await getDataDir()

const selected = await open({
directory: true,
multiple: false,
defaultPath: dataDir
});
// TODO: check permission of selected dir for server to write into

if (selected) {
setLocalSettings({ ...localSettings, dataDir: selected })
} else {
console.log('canceled');
}
} catch (error) {
console.error("failed to change data directory:", error);
toast({
title: "error",
description: "failed to change data directory.",
variant: "destructive",
duration: 3000,
});
}
}

const runSetup = async () => {
setIsSetupRunning(true);
try {
Expand Down Expand Up @@ -889,6 +920,32 @@ export function RecordingSettings({
</Popover>
</div>

<div className="flex flex-col space-y-2">
<Label
htmlFor="monitorIds"
className="flex items-center space-x-2"
>
<Folder className="h-4 w-4" />
<span>data directory</span>
</Label>

<Button
variant="outline"
role="combobox"
className="w-full justify-between"
onClick={handleDataDirChange}
>
<div className="inline-block flex gap-4">
{!!settings.dataDir ? "change directory" : "select directory"}
{localSettings.dataDir === settings.dataDir ?
<span className="text-muted-foreground text-sm"> current at: {settings.dataDir || "default directory"}</span> :
<span className="text-muted-foreground text-sm"> change to: {localSettings.dataDir || "default directory"}</span>
}
</div>
<ChevronsUpDown className="ml-2 h-4 w-4 shrink-0 opacity-50" />
</Button>
</div>

<div className="flex flex-col space-y-2">
<div className="flex items-center space-x-2">
<Switch
Expand Down
26 changes: 13 additions & 13 deletions screenpipe-app-tauri/components/screenpipe-status.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,8 @@ const HealthStatus = ({ className }: { className?: string }) => {
const { health } = useHealthCheck();
const [isDialogOpen, setIsDialogOpen] = useState(false);
const [isMac, setIsMac] = useState(false);
const { settings } = useSettings();
const { settings, getDataDir } = useSettings();
const [localDataDir, setLocalDataDir] = useState('');
const [isLogOpen, setIsLogOpen] = useState(false);
const [isFixingSetup, setIsFixingSetup] = useState(false);
const [isTroubleshootOpen, setIsTroubleshootOpen] = useState(false);
Expand Down Expand Up @@ -88,13 +89,8 @@ const HealthStatus = ({ className }: { className?: string }) => {

const handleOpenDataDir = async () => {
try {
const homeDirPath = await homeDir();

const dataDir =
platform() === "macos" || platform() === "linux"
? `${homeDirPath}/.screenpipe`
: `${homeDirPath}\\.screenpipe`;
await open(dataDir as string);
const dataDir = await getDataDir()
await open(dataDir);
} catch (error) {
console.error("failed to open data directory:", error);
toast({
Expand Down Expand Up @@ -383,19 +379,23 @@ const HealthStatus = ({ className }: { className?: string }) => {
settings.enableUiMonitoring
);

const handleOpenStatusDialog = async () => {
setLocalDataDir(await getDataDir())
setIsDialogOpen(true)
}

return (
<>
<Badge
variant="outline"
className="cursor-pointer bg-transparent text-foreground hover:bg-accent hover:text-accent-foreground"
onClick={() => setIsDialogOpen(true)}
onClick={handleOpenStatusDialog}
>
<Activity className="mr-2 h-4 w-4" />
status{" "}
<span
className={`ml-1 w-2 h-2 rounded-full ${statusColor} inline-block ${
statusColor === "bg-red-500" ? "animate-pulse" : ""
}`}
className={`ml-1 w-2 h-2 rounded-full ${statusColor} inline-block ${statusColor === "bg-red-500" ? "animate-pulse" : ""
}`}
/>
</Badge>
<Dialog open={isDialogOpen} onOpenChange={setIsDialogOpen}>
Expand Down Expand Up @@ -454,7 +454,7 @@ const HealthStatus = ({ className }: { className?: string }) => {
</div>

<Separator className="my-12" />
<DevModeSettings />
<DevModeSettings localDataDir={localDataDir} />

<Collapsible
open={isLogOpen}
Expand Down
52 changes: 31 additions & 21 deletions screenpipe-app-tauri/lib/hooks/use-settings.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { useState, useEffect } from "react";
import { createStore } from "@tauri-apps/plugin-store";
import { localDataDir, join } from "@tauri-apps/api/path";
import { localDataDir, join, homeDir } from "@tauri-apps/api/path";
import { platform } from "@tauri-apps/plugin-os";
import { Pipe } from "./use-pipes";
import posthog from "posthog-js";
Expand Down Expand Up @@ -148,8 +148,8 @@ export function useSettings() {
currentPlatform === "macos"
? "apple-native"
: currentPlatform === "windows"
? "windows-native"
: "tesseract";
? "windows-native"
: "tesseract";

console.log("loading settings", store);
// no need to call load() as it's done automatically
Expand Down Expand Up @@ -244,29 +244,29 @@ export function useSettings() {
const defaultIgnoredWindows =
currentPlatform === "macos"
? [
...ignoredWindowsInAllOS,
".env",
"Item-0",
"App Icon Window",
"Battery",
"Shortcuts",
"WiFi",
"BentoBox",
"Clock",
"Dock",
"DeepL",
"Control Center",
]
...ignoredWindowsInAllOS,
".env",
"Item-0",
"App Icon Window",
"Battery",
"Shortcuts",
"WiFi",
"BentoBox",
"Clock",
"Dock",
"DeepL",
"Control Center",
]
: currentPlatform === "windows"
? [
? [
...ignoredWindowsInAllOS,
"Nvidia",
"Control Panel",
"System Properties",
]
: currentPlatform === "linux"
? [...ignoredWindowsInAllOS, "Info center", "Discover", "Parted"]
: [];
: currentPlatform === "linux"
? [...ignoredWindowsInAllOS, "Info center", "Discover", "Parted"]
: [];

const savedIgnoredWindows = await store!.get<string[]>(
"ignoredWindows"
Expand Down Expand Up @@ -372,7 +372,17 @@ export function useSettings() {
}
};

return { settings, updateSettings, resetSetting };
const getDataDir = async () => {
const homeDirPath = await homeDir();

if (settings.dataDir) return settings.dataDir;

return platform() === "macos" || platform() === "linux"
? `${homeDirPath}/.screenpipe`
: `${homeDirPath}\\.screenpipe`;
}

return { settings, updateSettings, resetSetting, getDataDir };
}

async function initStore() {
Expand Down
Loading