Skip to content
peekcatPublic

About

This is a program developed for professional photographers or photography studios. It exposes your IPv6 address so that your clients can access a specific folder, select the photos they like for retouching, or download the photos you have already edited.

Resources

Stars

0 stars

Watchers

0 watching

Forks

Repository files navigation

PicShare

A self-hosted photo proofing & delivery tool for photographers. Clients browse and mark their favorites in a modern web album — no cloud upload, no messenger recompression. Deliver remotely over IPv6, or straight across the room on your own Wi-Fi.

version python platform license

English · 中文

Features

  • Professional proofing UI — an iOS-style album that elevates your brand, with a PhotoSwipe viewer (zoom / pan / gestures / keyboard).
  • Full RAW support — auto-generates previews for CR2 / CR3 / NEF / ARW / DNG / ORF / RW2 / PEF / SR2, decoded with bundled libraw (via rawpy) — no external tools to install.
  • One-tap selection — clients favorite photos in the browser; picks are kept as a per-album manifest (no file copying until you export).
  • Two ways to reach you — a public IPv6 link your client can open from anywhere (no port-forwarding, no NAT setup), plus a LAN link for in-person proofing that needs nothing from your ISP. PicShare detects both and labels which is which; you never pick a protocol.
  • Works everywhere — phones, tablets, and desktop browsers.
  • Fast tiered cache — multi-threaded thumbnail prewarm, plus on-demand large (1600px) and RAW "original" (HD) tiers with lazy loading.

Quickstart

Requirements

The desktop window uses your OS's native WebView (via pywebview):

  • macOS — WKWebView, built in. Nothing to install.
  • Windows — the WebView2 Runtime (bundled with Windows 10/11; if the window won't open, install the Evergreen WebView2 Runtime).
  • Linux — WebKit2GTK, e.g. sudo apt install gir1.2-webkit2-4.1 libwebkit2gtk-4.1-0 (package names vary by distro).

Install

Grab the package for your platform from the Releases page — no Python required.

Platform Download How to install
macOS (Apple Silicon) PicShare-<ver>-macos-arm64.dmg Open the DMG, drag PicShare onto Applications
macOS (Intel) PicShare-<ver>-macos-x64.dmg Same as above
Windows 10/11 (x64) PicShare-Setup-<ver>-x64.exe Double-click, follow the wizard — installs per-user, no admin rights needed
Linux (x64) PicShare-<ver>-linux-x64.tar.gz Extract, run ./PicShare
Blocked on first launch? That is expected — here is how to allow it

PicShare is not code-signed (Apple and Windows certificates are a paid, per-year expense), so both systems warn about software from an "unidentified developer". The warning is about the missing signature — nothing was found in the app.

  • macOS — double-click PicShare once (it gets blocked), then open System Settings → Privacy & Security, scroll down, click Open Anyway. On macOS 13 and earlier: System Preferences → Security & Privacy → General → Open Anyway. Terminal alternative: xattr -dr com.apple.quarantine /Applications/PicShare.app
  • Windows — SmartScreen shows "Windows protected your PC". Click More info → Run anyway.

You only need to do this once.

First run

Launch PicShare, then in the desktop window:

  1. Click Select to choose your photo root directory (the folder that holds your album subfolders).
  2. Click the 网络 (Network) chip and check which addresses are available — 🌐 public (client can be anywhere) and/or 📶 LAN (same Wi-Fi only).
  3. In 🔗 Share management, pick an album, set an expiry → Generate & copy link (no passcode by default; enable one for sensitive albums).
  4. Send the link (http://[...]:5000/share/<token>) to your client. If you added a passcode, send it separately (buttons let you re-copy the link / passcode anytime).

How it works

  • Photographer — run the app, choose your photo root, then generate a dedicated share link (with optional expiry and passcode) for an album and send it to the matching client.
  • Client — open the link to browse, mark favorites, and view full-resolution photos (RAW is served as an on-demand high-res JPEG). No album name to type. A skippable one-screen guide appears on first open, and the ? in the top bar brings it back.
  • Collect — click Export in the desktop app to copy the selected originals into 被标记的照片/<album>/, then it opens in your file manager.

Access Control

PicShare uses a capability-URL model rather than guessable album names:

  • Each album is bound to an unguessable random token (/share/<token>); the album is derived server-side, so clients cannot specify an album name in the URL and can neither see nor guess others' albums.
  • The token is a strong random credential (192-bit). For most cases one link is enough — no passcode needed.
  • Optionally add a passcode for sensitive albums (off by default): a random 4-character alphanumeric code, sent separately from the link (it is not embedded in the URL, so forwarding the link doesn't leak it). The client types it once in the browser.
  • Links can carry an expiry (3 / 7 / 14 days, default 3; auto-invalidates).
  • You can revoke any link at any time, or re-copy its link / passcode.
  • Tokens and passcodes (if set) live in <root>/._picshare/tokens.json (a local hidden file), managed by the desktop app and read-only-verified by the web server.

Project Layout

This repo has been refactored from the original single file into a standard src-layout Python project.

src/picshare/
├── __main__.py        # `python -m picshare` entry
├── desktop.py         # desktop entry: pywebview admin window + waitress public server
├── config.py          # ServerState config, extensions, cache/data dirs
├── settings.py        # user-level settings persistence (remembers the root dir, etc.)
├── status.py          # unified logging (logging → console / file / run-log panel)
├── network.py         # address detection: public IPv6 + LAN IPv4 (Windows / macOS / Linux)
├── paths.py           # safe_join path-safety helper
├── preview.py         # thumbnail / large / RAW-HD generation (rawpy fallback + cache version stamp)
├── tokens.py          # access-token storage & verification (capability URLs)
├── selections.py      # client selection manifest storage
├── admin/             # admin side (pywebview, in-process js_api, no public HTTP endpoints)
│   ├── api.py         # Python API exposed to the admin page
│   └── templates.py   # admin single-page HTML (album cards / sharing / run log)
└── web/               # public web service (client /share access)
    ├── app.py         # Flask app & token-scoped routes
    ├── templates.py   # album / landing / passcode page templates
    └── static/photoswipe/   # bundled PhotoSwipe viewer (offline)

Build from source

Requires Python 3.10+.

pip install -e .
picshare            # or: python -m picshare

To produce the distributable packages yourself — PyInstaller cannot cross-compile, so each one has to be built on its own OS:

./scripts/build-macos.sh       # → dist/PicShare.app + dist/PicShare-<ver>-macos-<arch>.dmg
.\scripts\build-windows.ps1    # → dist/PicShare/ + dist/PicShare-Setup-<ver>-x64.exe (needs Inno Setup 6.5+)
./scripts/build-linux.sh       # → dist/PicShare/

Security Notes

Access control is token-based (see above), which is far stronger than "guess the album name." A few inherent limits still apply:

  • The link is the credential — a capability URL is a bearer secret; anyone with the link can access it. For sensitive albums, add a passcode and/or expiry, and avoid sharing links on public channels.
  • The service now also listens on IPv4 — anyone on the same LAN who has the link can open it. Since the token has always been the credential and the IPv6 side is exposed to the whole internet, this narrows rather than widens the exposure — but on an untrusted network (a hotel, a shared studio), prefer a passcode.
  • Plain HTTP — TLS is not enabled; an on-path attacker could intercept tokens and photos. Strong encryption needs a reverse proxy / tunnel (e.g. Caddy, Cloudflare Tunnel) — a future direction.
  • No passcode rate-limiting — passcode checks aren't rate-limited yet, so a short passcode is theoretically brute-forceable by an attacker who already holds the token; rate-limiting / lockout is a planned hardening.

Always make sure the chosen photo root contains only the photos you're willing to deliver.

License

Source-available under the PolyForm Noncommercial License 1.0.0 — you may use, modify, and share it for noncommercial purposes only. Commercial use is not permitted.

Note: because of the noncommercial restriction, this is source-available, not OSI "open source."

About

This is a program developed for professional photographers or photography studios. It exposes your IPv6 address so that your clients can access a specific folder, select the photos they like for retouching, or download the photos you have already edited.

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages