Skip to content

Commit 09a98c0

Browse files
committed
v0.6.16: fix settings persistence in AppImage — use DATA_DIR
When running as a PyInstaller bundle, __file__ resolves to a temp extraction dir (/tmp/_MEIxxxxx/) that is deleted on exit, so all saved credentials and config were silently lost. Fix: introduce DATA_DIR = ~/.auto_note/ when sys.frozen is set, = PROJECT_DIR otherwise (source runs unchanged). All credential and config file paths (config.json, *_token.txt, *_api.txt, manifest.json, course data dirs) now use DATA_DIR.
1 parent 58d6902 commit 09a98c0

1 file changed

Lines changed: 22 additions & 12 deletions

File tree

gui.py

Lines changed: 22 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,16 @@
3232
"generate": PROJECT_DIR / "note_generation.py",
3333
}
3434

35+
# User data directory: persistent across app restarts.
36+
# When running as a PyInstaller bundle (AppImage / .exe), __file__ resolves to
37+
# a temporary extraction folder that is deleted on exit — any files written
38+
# there are lost. Use ~/.auto_note/ instead so credentials and config survive.
39+
if getattr(sys, "frozen", False):
40+
DATA_DIR = Path.home() / ".auto_note"
41+
else:
42+
DATA_DIR = PROJECT_DIR
43+
DATA_DIR.mkdir(parents=True, exist_ok=True)
44+
3545
COURSES: dict[int, str] = {} # populated from Canvas API after token is entered
3646

3747
_SKIP_KEYWORDS = [
@@ -44,8 +54,8 @@ def _load_courses_from_canvas() -> str:
4454
"""Fetch active courses from Canvas and update the global COURSES dict.
4555
Returns "" on success, or a human-readable error string on failure."""
4656
COURSES.clear()
47-
token_file = PROJECT_DIR / "canvas_token.txt"
48-
config_file = PROJECT_DIR / "config.json"
57+
token_file = DATA_DIR / "canvas_token.txt"
58+
config_file = DATA_DIR / "config.json"
4959
token = token_file.read_text().strip() if token_file.exists() else ""
5060
if not token:
5161
return "Canvas token not saved — enter it in Settings → API Keys."
@@ -91,7 +101,7 @@ def _load_courses_from_canvas() -> str:
91101
# ── Pipeline state helpers ────────────────────────────────────────────────────
92102

93103
def _manifest() -> dict:
94-
p = PROJECT_DIR / "manifest.json"
104+
p = DATA_DIR / "manifest.json"
95105
return json.loads(p.read_text()) if p.exists() else {}
96106

97107
def _video_status(course_id: int) -> tuple[int, int]:
@@ -101,16 +111,16 @@ def _video_status(course_id: int) -> tuple[int, int]:
101111
return done, len(items)
102112

103113
def _caption_count(course_id: int) -> int:
104-
d = PROJECT_DIR / str(course_id) / "captions"
114+
d = DATA_DIR / str(course_id) / "captions"
105115
return len(list(d.glob("*.json"))) if d.exists() else 0
106116

107117
def _alignment_count(course_id: int) -> int:
108-
d = PROJECT_DIR / str(course_id) / "alignment"
118+
d = DATA_DIR / str(course_id) / "alignment"
109119
return len([f for f in d.glob("*.json")
110120
if "compact" not in f.name]) if d.exists() else 0
111121

112122
def _notes_path(course_id: int) -> Path | None:
113-
d = PROJECT_DIR / str(course_id) / "notes"
123+
d = DATA_DIR / str(course_id) / "notes"
114124
if d.exists():
115125
mds = list(d.glob("*.md"))
116126
return mds[0] if mds else None
@@ -1059,7 +1069,7 @@ def _field_row(label: str, tf: ft.TextField) -> ft.Row:
10591069

10601070
# ── Connection settings (config.json) ────────────────────────────────────
10611071

1062-
config_file = PROJECT_DIR / "config.json"
1072+
config_file = DATA_DIR / "config.json"
10631073

10641074
def _load_config() -> dict:
10651075
return json.load(open(config_file)) if config_file.exists() else {}
@@ -1073,10 +1083,10 @@ def _save_config_all(data: dict) -> None:
10731083
# _v holds the live text for every field; on_change keeps it in sync.
10741084
# Reading tf.value without on_change returns the *initial* value only.
10751085
_cfg = _load_config()
1076-
canvas_file = PROJECT_DIR / "canvas_token.txt"
1077-
openai_file = PROJECT_DIR / "openai_api.txt"
1078-
anthropic_file = PROJECT_DIR / "anthropic_key.txt"
1079-
gemini_file = PROJECT_DIR / "gemini_api.txt"
1086+
canvas_file = DATA_DIR / "canvas_token.txt"
1087+
openai_file = DATA_DIR / "openai_api.txt"
1088+
anthropic_file = DATA_DIR / "anthropic_key.txt"
1089+
gemini_file = DATA_DIR / "gemini_api.txt"
10801090

10811091
_v = {
10821092
"canvas_url": _cfg.get("CANVAS_URL", ""),
@@ -1162,7 +1172,7 @@ def _do_refresh():
11621172
ft.Row(controls=[
11631173
ft.Text("Project dir", size=11,
11641174
color=ft.Colors.with_opacity(0.5, ft.Colors.WHITE)),
1165-
ft.Text(str(PROJECT_DIR), size=11, selectable=True,
1175+
ft.Text(str(DATA_DIR), size=11, selectable=True,
11661176
color=ft.Colors.with_opacity(0.7, ft.Colors.WHITE)),
11671177
], spacing=8),
11681178
], spacing=10))

0 commit comments

Comments
 (0)