Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
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
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -88,6 +88,8 @@ test_results.txt
smoke_test_output.txt
verify_result.txt
*test_output.txt
test_image*


**/*fail*.txt
**/*final*.txt
12 changes: 11 additions & 1 deletion ChangeLog.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,16 @@
# ChangeLog

Todo: Make it work on Linux / Mac. Create Windows .exe. Write better documentation / help. Add splash screen / icon. Fix raw image support.
Todo: More testing Linux / Mac. Create Windows .exe. Write better documentation / help. Add splash screen / icon. Fix raw image support.

## 1.5.9 (2026-02-16)

- Full-Screen Mode: Press F11 to toggle fullscreen in loupe view
- Spark Line Display: Grid view now shows upload progress indicators per folder.
- Optimized grid view performance and prefetch behavior.
- Added EXIF brief display in status bar showing ISO, aperture, shutter speed, and capture time.
- Enhanced metadata display with camera-style shutter speed formatting.
- Added new thumbnail badges for Backups (Bk) and Developed (D) variants.
- Improved cache eviction handling and thread-safety for concurrent operations.

## 1.5.8 (2026-02-13)

Expand Down
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ This tool is optimized for speed, using `libjpeg-turbo` for decoding, aggressive
- **Crop:** Added the ability to crop and rotate images via the cr(O)p hotkey (or right mouse click). It can be a freeform crop, or constrained to several popular aspect ratios.
- **Zoom & Pan:** Smooth zooming and panning.
- **Stack Selection:** Group images into stacks (`[`, `]`) and select them for processing (`S`).
- **Speak Line**: In grid view, a spark line is visible on each folder, so you can see how far you have gotten in uploading photos in each directory.
- **Spark Line**: In grid view, a spark line is visible on each folder, so you can see how far you have gotten in uploading photos in each directory.
- **Helicon Focus Integration:** Launch Helicon Focus with your selected RAW files with a single keypress (`Enter`).
- **Instant Navigation:** Sub-10ms next/previous image switching, high performance decoding via `PyTurboJPEG`.
- **Image Editor:** Built-in editor with exposure, contrast, white balance, sharpness, and more (E key)
Expand Down
777 changes: 519 additions & 258 deletions faststack/app.py

Large diffs are not rendered by default.

9 changes: 7 additions & 2 deletions faststack/check_daemon.py
Original file line number Diff line number Diff line change
@@ -1,15 +1,20 @@
import threading
from concurrent.futures import ThreadPoolExecutor


def set_daemon():
try:
threading.current_thread().daemon = True
print(f"Set daemon for {threading.current_thread().name}")
except Exception as e:
print(f"Failed to set daemon for {threading.current_thread().name}: {e}")


def check_daemon():
return threading.current_thread().daemon

with ThreadPoolExecutor(max_workers=1, initializer=set_daemon) as executor:
print(f"Result: {executor.submit(check_daemon).result()}")

if __name__ == "__main__":
with ThreadPoolExecutor(max_workers=1, initializer=set_daemon) as executor:
print(f"Result: {executor.submit(check_daemon).result()}")

22 changes: 0 additions & 22 deletions faststack/debug_path_norm.py

This file was deleted.

43 changes: 25 additions & 18 deletions faststack/deletion_types.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,11 +11,12 @@
from typing import Any, List, Optional, Tuple



from enum import Enum


class DeletionErrorCodes(str, Enum):
"""Standardized error codes for deletion failures."""

RECYCLE_FAILED = "recycle_failed"
PERMISSION_DENIED = "permission_denied"
TRASH_FULL = "trash_full"
Expand Down Expand Up @@ -115,29 +116,35 @@ def _to_path(v):

successes = []
for s in raw.get("successes", []):
successes.append(DeleteRecord(
jpg=_to_path(s.get("jpg")),
recycled_jpg=_to_path(s.get("recycled_jpg")),
raw=_to_path(s.get("raw")),
recycled_raw=_to_path(s.get("recycled_raw")),
))
successes.append(
DeleteRecord(
jpg=_to_path(s.get("jpg")),
recycled_jpg=_to_path(s.get("recycled_jpg")),
raw=_to_path(s.get("raw")),
recycled_raw=_to_path(s.get("recycled_raw")),
)
)

warnings = []
for w in raw.get("warnings", []):
warnings.append(DeleteWarning(
jpg=_to_path(w.get("jpg")),
raw=_to_path(w.get("raw")),
message=w.get("message", ""),
))
warnings.append(
DeleteWarning(
jpg=_to_path(w.get("jpg")),
raw=_to_path(w.get("raw")),
message=w.get("message", ""),
)
)

failures = []
for f in raw.get("failures", []):
failures.append(DeleteFailure(
jpg=_to_path(f.get("jpg")),
raw=_to_path(f.get("raw")),
code=f.get("code", ""),
message=f.get("message", ""),
))
failures.append(
DeleteFailure(
jpg=_to_path(f.get("jpg")),
raw=_to_path(f.get("raw")),
code=f.get("code", ""),
message=f.get("message", ""),
)
)

return cls(
job_id=raw.get("job_id", 0),
Expand Down
Loading