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
457 changes: 370 additions & 87 deletions assets/js/remotebuzzer-server.js

Large diffs are not rendered by default.

389 changes: 322 additions & 67 deletions assets/js/sync-to-drive.js

Large diffs are not rendered by default.

14 changes: 4 additions & 10 deletions docs/faq/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -259,19 +259,13 @@ Take a look for "Loaded Configuration File" to get the path of your php.ini, you

---

## Automatic picture syncing to USB stick
## USB Sync & Move2USB — syncing pictures to a USB stick

This feature will automatically and in regular intervals copy (sync) new pictures to a plugged-in USB stick
Photobooth can **automatically sync** new pictures and videos to a USB stick at regular intervals (**USB Sync**), or you can trigger a **one-time copy or move** of all media via HTTP/socket.io/hardware button (**Move2USB**).

Use the [Photobooth Setup Wizard](https://photoboothproject.github.io/install/setup_wizard) to get the operating system setup in place.
Both features require mount permissions for `www-data` (Polkit + sudoers). Use the [Photobooth Setup Wizard](https://photoboothproject.github.io/install/setup_wizard) → **Permissions → USB Sync policy** to set them up.

- 6. Permissions -> USB Sync policy

The target USB device is selected through the admin panel.

A USB drive / stick can be identified either by the USB stick label (e.g. `photobooth`), the operating system specific USB device name (e.g. `/dev/sda1`) or the USB device system subsystem name (e.g. `sda`). The preferred method would be the USB stick label (for use of a single USB stick) or the very specific USB device name, for different USB stick use. The default config will look for a drive with the label photobooth. The script only supports one single USB stick connected at a time

Pictures will be synced to the USB stick matched by the pattern, as long as it is mounted (aka USB stick is plugged in)
See the full guide: **[USB Sync & Move2USB](usb-sync.md)** — setup, configuration, mount strategy, and troubleshooting.

Debugging: Check the server logs for errors at the Debug panel: [http://localhost/admin/debugpanel](http://localhost/admin/debugpanel) (
or [http://localhost/photobooth/admin/debugpanel](http://localhost/photobooth/admin/debugpanel)).
Expand Down
5 changes: 3 additions & 2 deletions docs/faq/remote-button.md
Original file line number Diff line number Diff line change
Expand Up @@ -60,8 +60,9 @@ Notes
## 3) Remote trigger via Socket.io

- Channel: `photobooth-socket`
- Commands: `start-picture`, `start-collage`, `collage-next`, `start-custom`, `start-video`, `print`, `rotary-cw`, `rotary-ccw`, `rotary-btn-press`, `move2usb`
- Commands: `start-picture`, `start-collage`, `collage-next`, `collage-wait-for-next`, `start-custom`, `start-video`, `start-move2usb`, `print`, `rotary-cw`, `rotary-ccw`, `rotary-btn-press`, `completed`, `in-progress`
- Response: `completed` after the workflow finishes.
- `start-move2usb` copies (or moves) all photos/videos to the configured USB stick — see [USB Sync & Move2USB](usb-sync.md) for setup and permissions.

## 4) Remote trigger via simple web requests (HTTP)

Expand All @@ -76,7 +77,7 @@ Notes
- `[Base URL]/commands/start-custom`
- `[Base URL]/commands/start-print`
- `[Base URL]/commands/start-video`
- `[Base URL]/commands/start-move2usb`
- `[Base URL]/commands/start-move2usb` (see [USB Sync & Move2USB](usb-sync.md))
- `[Base URL]/commands/reboot-now`
- `[Base URL]/commands/shutdown-now`
- `[Base URL]/commands/rotary-cw`
Expand Down
200 changes: 200 additions & 0 deletions docs/faq/usb-sync.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,200 @@
# USB Sync & Move2USB

Photobooth offers two ways to get your photos and videos onto a USB stick:

| Feature | Purpose | Trigger |
|---------|---------|---------|
| **USB Sync** | Automatic background sync at a regular interval | Runs continuously while Photobooth is open |
| **Move2USB** | One-shot copy **or** move of all media | Manual — HTTP endpoint or socket.io command |

Both features share the same USB device identifier (Adminpanel → **USB Sync → USB device identifier**) and the same Linux mount permissions.

---

## Prerequisites

- **Linux only** — Windows is not supported.
- **rsync** must be installed (`sudo apt install rsync`).
- A **USB stick** formatted as **FAT32** or **exFAT** (recommended for cross-platform compatibility). The volume label should match the identifier configured in the admin panel (default: `photobooth`).
- Mount permissions for the `www-data` user (see [Permissions setup](#permissions-setup) below).

---

## Permissions setup

The web-server user (`www-data`) needs permission to mount and unmount USB drives.
Photobooth ships two complementary mechanisms that are installed via the **Photobooth Setup Wizard**:

1. **Polkit rule** — allows `www-data` to call `udisksctl mount` / `udisksctl unmount` without a password.
2. **sudoers rule** (`/etc/sudoers.d/021_www-data-usb-sync`) — passwordless `sudo mount /dev/* /media/*`, `sudo umount /dev/*` and `sudo mkdir -p /media/*` as fallback when udisksctl is unavailable. Both `/bin` and `/usr/bin` paths are covered for portability.

### Installing via the Setup Wizard

Download and run the Setup Wizard:

```
wget -O install-photobooth.sh https://raw.githubusercontent.com/PhotoboothProject/photobooth/dev/install-photobooth.sh
sudo bash install-photobooth.sh
```

Then choose:

- **6 Permissions → 4 USB Sync policy**

The wizard will:

- Install the Polkit rule for udisksctl.
- Install the sudoers rule for mount/umount/mkdir.
- Disable desktop auto-mount (pcmanfm `mount_on_startup`, `mount_removable`, `autorun` in both the system default and user profile config) to avoid permission conflicts.
- Remove any legacy `020_www-data-usb` sudoers file and `50-photobooth-udisks.rules` polkit file.

**Note:** USB mount permissions are also installed automatically when running **2 Fix general permissions** or during a fresh Photobooth install. The dedicated "USB Sync policy" menu entry is only needed to re-apply or remove the rules individually.

Run the same menu entry again after OS upgrades to re-apply the rules.

### Removing permissions

Run **6 Permissions → 4 USB Sync policy** again and answer **No** when asked to set up the policy. The wizard removes Polkit rules, sudoers rules, and the legacy files.

---

## USB Sync (automatic)

USB Sync runs as a background Node.js process (`sync-to-drive.js`) that is started automatically when Photobooth is opened in the browser (provided the feature is enabled).

### How it works

1. The process looks for a USB device matching the configured identifier (label, device path, or device name).
2. It mounts the device if it is not already mounted:
- First via `udisksctl mount`.
- Fallback: `sudo mount` to `/media/<label>` with automatic FAT32/exFAT uid/gid options.
3. It runs `rsync` to incrementally copy new `jpg`, `gif`, `mp4` files from the Photobooth data directory to the USB stick.
4. Deleted images are backed up into a `deleted/` folder on the USB stick (rsync `--backup-dir`).
5. After sync completes, the process sleeps for the configured interval and starts over.

### Device detection

The device is matched (case-insensitive) by:

- **Volume label** (recommended) — e.g. `photobooth`
- **Block device path** — e.g. `/dev/sda1`
- **Device short name** — e.g. `sda1`

If `lsblk` does not report the label (e.g. in LXC containers or after a USB reconnect), Photobooth falls back to `blkid` which reads the label directly from the block device.

### Configuration

Open the Admin Panel → **USB Sync**:

| Setting | Description |
|---------|-------------|
| **Enable** | Turn automatic USB Sync on or off. |
| **Automated syncing interval** | Seconds between sync attempts (default: 300). |
| **USB device identifier** | The value used to find the USB stick — typically the volume label (default: `photobooth`). |

### File types synced

`jpg`, `gif`, `mp4` (and the internal `chk` verification files).

---

## Move2USB (manual copy / move)

Move2USB lets you copy — or move — **all** current photos and videos to the USB stick with a single action.

### Modes

| Mode | Behaviour |
|------|-----------|
| **copy** | Copies all media to the USB stick. Originals remain on the Photobooth. |
| **move** | Copies all media to the USB stick **and** deletes the originals plus the Photobooth image database after a successful, verified sync. |

### Enabling Move2USB

1. Adminpanel → **Hardware Button → Enable Hardware Buttons** must be active.
2. Adminpanel → **Hardware Button → Move2USB mode** — choose `copy` or `move` (set to `disabled` to hide the feature).
3. The **USB device identifier** under USB Sync must point to a valid USB stick.

### Triggering Move2USB

- **HTTP endpoint:** `http://<IP>:<Port>/commands/start-move2usb` — requires Hardware Buttons enabled and Move2USB mode not `disabled`.
- **Socket.io:** emit `photobooth-socket` → `start-move2usb`

### Copy verification

Move2USB creates a `copy.chk` marker file in the Photobooth data folder before rsync and expects it to appear on the USB stick after sync. If the marker is missing on the USB stick after rsync, the sync is treated as **failed** and no files are deleted (even in `move` mode). After successful verification, both the local and USB-side `copy.chk` files are cleaned up automatically.

### What gets deleted in "move" mode

Only after a verified successful sync:

1. All `jpg`, `gif`, `mp4` files in the Photobooth data directory.
2. The Photobooth image database file (`<dbname>.txt`).

---

## Mount strategy (both features)

Photobooth uses a layered approach to mount USB drives:

1. **udisksctl** — preferred, works with the Polkit rule.
2. **findmnt check** — if udisksctl output was ambiguous, verify via `findmnt`.
3. **sudo mount** — fallback using the sudoers rule; mounts to `/media/<label>`.

For **FAT32** (`vfat`) and **exFAT** volumes the mount options `umask=0000,uid=<uid>,gid=<gid>` (using the numeric uid/gid of the running process, typically `33` for `www-data`) are set automatically so the web-server process can write to the stick.

If a drive is already mounted but **not writable** (e.g. auto-mounted by the desktop with different uid/gid), Photobooth unmounts and re-mounts it with the correct options.

Unmounting follows the same order: udisksctl first, `sudo umount` as fallback.

**When does each feature unmount?**

- **USB Sync** keeps the stick mounted between sync intervals and only unmounts on process termination (SIGTERM/SIGHUP/SIGINT).
- **Move2USB** unmounts the stick after every sync operation (before deleting local files in `move` mode).

---

## Preparing a USB stick

1. Format the stick as **FAT32** (for sticks ≤ 32 GB) or **exFAT** (for larger sticks).
2. Set the volume label to `photobooth` (or whatever you configure as the USB device identifier).
- Linux: `sudo fatlabel /dev/sdX1 photobooth` (FAT32) or `sudo exfatlabel /dev/sdX1 photobooth` (exFAT).
- Windows: right-click the drive → Rename.
- macOS: Disk Utility → rename the volume.
3. Plug the stick into the Photobooth host.

---

## Troubleshooting

### USB stick not detected

- Verify the label: `lsblk -o NAME,LABEL,FSTYPE,MOUNTPOINT` — the label must match the configured identifier (case-insensitive).
- If `lsblk` shows no label, try `blkid` — Photobooth uses this as a fallback.
- Confirm the device is a **USB** device (`lsblk -o NAME,SUBSYSTEMS` should contain `usb`).

### Permission errors / mount failures

- Re-run the Setup Wizard → **Permissions → USB Sync policy**.
- Check that Polkit and sudoers are in place:
- `ls -l /etc/polkit-1/localauthority/50-local.d/photobooth.pkla` or `/etc/polkit-1/rules.d/photobooth.rules`
- `ls -l /etc/sudoers.d/021_www-data-usb-sync`
- Disable desktop auto-mount (e.g. pcmanfm volume handling) — it can race with Photobooth and mount with the wrong uid.

### Sync not running / nothing copied

- Is USB Sync enabled in the Admin Panel?
- Check the server logs at the Debug panel: [http://localhost/admin/debugpanel](http://localhost/admin/debugpanel).
- Look for `[synctodrive]` log lines — they show device detection, mount status, and rsync output.

### Move2USB fails or does not delete files

- Check Debug panel for `[remotebuzzer]` log lines mentioning `move2usb`.
- If the log says "sync verification failed (copy.chk missing)", the rsync did not complete successfully — check USB stick space and permissions.
- Files are only deleted in `move` mode **and** only after verified sync.

### FAT32 / exFAT write issues

- Ensure the stick is not write-protected (physical switch on some USB sticks).
- Re-format the stick and re-label it.
- If mounted by another process, Photobooth will unmount and re-mount with proper options — check the log for "not writable, unmounting" messages.
51 changes: 42 additions & 9 deletions install-photobooth.sh
Original file line number Diff line number Diff line change
Expand Up @@ -1111,6 +1111,12 @@ function general_permissions() {
info "Permissions" "Disabling camera automount."
chmod -x /usr/lib/gvfs/gvfs-gphoto2-volume-monitor >/dev/null 2>&1 || warn "Failed to disable camera automount"

# Allow www-data to mount/unmount USB drives (required for sync-to-drive and move2usb)
info "Permissions" "Setting up USB mount permissions for www-data."
create_polkit_usb_rule || warn "Failed to create polkit USB rule"
install_usb_sudoers || warn "Failed to install USB sudoers rule"
disable_automount || info "Permissions" "No desktop automount config found to adjust."

return 0
}

Expand Down Expand Up @@ -1263,6 +1269,29 @@ EOF
fi
}

function install_usb_sudoers() {
local sudoers_file="/etc/sudoers.d/021_www-data-usb-sync"
# Portable paths: some distros use /bin vs /usr/bin for mount/umount/mkdir.
cat >"$sudoers_file" <<'EOF'
# Photobooth USB Sync — passwordless mount/umount/mkdir for www-data (sync-to-drive.js, move2usb).
# Use together with Polkit rules for udisksctl; this covers sudo fallbacks in the Node scripts.
Cmnd_Alias PHOTOBOOTH_USB_SYNC = /bin/mount /dev/* /media/*, /usr/bin/mount /dev/* /media/*, /bin/mount -o * /dev/* /media/*, /usr/bin/mount -o * /dev/* /media/*, /bin/umount /dev/*, /usr/bin/umount /dev/*, /bin/mkdir -p /media/*, /usr/bin/mkdir -p /media/*
www-data ALL=(root) NOPASSWD: PHOTOBOOTH_USB_SYNC
EOF

chmod 440 "$sudoers_file"

if visudo -cf "$sudoers_file" >/dev/null 2>&1; then
info "Setup" "Installed USB sudoers rule for www-data at $sudoers_file"
rm -f /etc/sudoers.d/020_www-data-usb 2>/dev/null || true
return 0
else
error "Invalid sudoers file created at $sudoers_file. Please check manually."
rm -f "$sudoers_file"
return 1
fi
}

function create_polkit_usb_rule() {
local PKLA_DIR="/etc/polkit-1/localauthority/50-local.d"
local RULES_DIR="/etc/polkit-1/rules.d"
Expand All @@ -1281,7 +1310,7 @@ EOF
elif [[ -d "$RULES_DIR" ]]; then
cat >"$RULES_DIR/photobooth.rules" <<'EOF'
polkit.addRule(function(action, subject) {
if (subject.isUser && subject.user == "www-data" &&
if (subject.user == "www-data" &&
(action.id.indexOf("org.freedesktop.udisks2.filesystem-mount") == 0 ||
action.id.indexOf("org.freedesktop.udisks2.filesystem-unmount") == 0)) {
return polkit.Result.YES;
Expand All @@ -1298,10 +1327,16 @@ EOF
function remove_polkit_usb_rule() {
local PKLA_FILE="/etc/polkit-1/localauthority/50-local.d/photobooth.pkla"
local RULES_FILE="/etc/polkit-1/rules.d/photobooth.rules"
local LEGACY_RULES_FILE="/etc/polkit-1/rules.d/50-photobooth-udisks.rules"
local SUDOERS_FILE_LEGACY="/etc/sudoers.d/020_www-data-usb"
local SUDOERS_FILE="/etc/sudoers.d/021_www-data-usb-sync"
local REMOVED=false

[[ -f "$PKLA_FILE" ]] && rm -f "$PKLA_FILE" && REMOVED=true
[[ -f "$RULES_FILE" ]] && rm -f "$RULES_FILE" && REMOVED=true
[[ -f "$LEGACY_RULES_FILE" ]] && rm -f "$LEGACY_RULES_FILE" && REMOVED=true
[[ -f "$SUDOERS_FILE_LEGACY" ]] && rm -f "$SUDOERS_FILE_LEGACY" && REMOVED=true
[[ -f "$SUDOERS_FILE" ]] && rm -f "$SUDOERS_FILE" && REMOVED=true

$REMOVED && return 0 || return 1
}
Expand Down Expand Up @@ -1375,17 +1410,15 @@ function disable_automount() {

function set_usb_sync() {
if whiptail --title "USB Sync" \
--yesno "Setup USB Sync policy?\n\nThis is needed to use the USB Sync feature of Photobooth.\nUSB Sync can be activated via Adminpanel." \
--yesno "Setup USB Sync policy?\n\nInstalls Polkit rules for udisksctl and sudoers for mount/umount/mkdir as www-data.\nAlso tries to disable desktop auto-mount to avoid permission conflicts.\nUSB Sync is enabled in the Admin panel." \
12 60; then

if create_polkit_usb_rule; then
if disable_automount; then
confirm "USB Sync" "USB Sync policy created and auto mount settings updated successfully."
else
confirm "USB Sync" "USB Sync policy created, but no configuration file was found to adjust auto mount."
fi
create_polkit_usb_rule || warn "Polkit USB rule could not be created; udisksctl may still need manual policy."
install_usb_sudoers || warn "USB sudoers rule could not be installed; sudo mount fallbacks may fail."
if disable_automount; then
confirm "USB Sync" "USB Sync policy and auto-mount adjustments applied."
else
confirm "USB Sync" "Failed to create USB Sync policy!"
confirm "USB Sync" "USB Sync Polkit/sudoers applied; no pcmanfm volume config found to adjust auto-mount."
fi

else
Expand Down
1 change: 1 addition & 0 deletions mkdocs_remote.yml
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@ nav:
- Screensaver: faq/screensaver.md
- Tutorials: faq/tutorials.md
- Remote Buttons: faq/remote-button.md
- USB Sync & Move2USB: faq/usb-sync.md
- Printer Troubleshooting: faq/printer-troubleshooting.md
- gphoto2 Troubleshooting: faq/gphoto2-troubleshooting.md
- GO2RTC Troubleshooting: faq/go2rtc-troubleshooting.md
Expand Down
Loading
Loading