rename applephotos to photoscli, update module path to gitea.k3s.k0.nu/tools/photocli

This commit is contained in:
Ein Anderssono
2026-06-11 20:29:06 +02:00
parent e48e20ad18
commit ca3a3e4a2a
6 changed files with 43 additions and 40 deletions
+3 -3
View File
@@ -1,5 +1,5 @@
BINARY := ./bin/applephotos
MODULE := github.com/einand/applephotos
BINARY := ./bin/photoscli
MODULE := gitea.k3s.k0.nu/tools/photocli
BRIDGE_DIR := bridge
OBJ := $(BRIDGE_DIR)/photokit_bridge.o
LIB := $(BRIDGE_DIR)/libphotokit_bridge.a
@@ -21,7 +21,7 @@ $(STUB_OBJ): $(BRIDGE_DIR)/photokit_bridge_stub.c $(BRIDGE_DIR)/photokit_bridge.
cc -c -o $@ $<
build: $(LIB)
go build -o $(BINARY) $(MODULE)/cmd/applephotos
go build -o $(BINARY) $(MODULE)/cmd/photoscli
test: $(STUB_LIB)
go test -tags=test -coverprofile=coverage.out -covermode=atomic -coverpkg=./... ./...
+28 -25
View File
@@ -1,26 +1,26 @@
# applephotos
# photoscli
`applephotos` is a small macOS-only CLI written in Go that reads data from Apple Photos through a PhotoKit bridge.
`photoscli` is a small macOS-only CLI written in Go that reads data from Apple Photos through a PhotoKit bridge.
It supports five tasks:
- listing albums
- listing asset IDs and filenames in an album
- listing asset IDs, filenames, and cloud status in an album
- showing the folder and album tree
- backing up all albums into the Photos folder tree
- exporting resized JPEG previews or original files from an album
## What The Code Does
The executable lives in `cmd/applephotos` and calls into `internal/photos`, which wraps an Objective-C bridge in `bridge/`.
The executable lives in `cmd/photoscli` and calls into `internal/photos`, which wraps an Objective-C bridge in `bridge/`.
Current behavior:
- `albums` prints one line per album as `<album-id>\t<title>`
- `photos --album-id <id-or-title>` prints one asset local identifier and filename per line; accepts either a PhotoKit local identifier or an album title
- `photos --album-id <id-or-title>` prints one asset per line as `<id>\t<filename>\t<cloud>`; accepts either a PhotoKit local identifier or an album title
- `tree` prints the human-readable folder and album hierarchy from Apple Photos
- `backup-all --out <dir> [--size <px>] [--originals]` exports every album into a matching folder tree under the output directory
- `export --album-id <id-or-title> --out <dir> [--size <px>] [--originals]` exports either JPEG previews or original files and reports the number exported on stderr; `--album-id` accepts either a PhotoKit local identifier or an album title
- `backup-all --out <dir> [--size <px>] [--originals]` exports every album into a matching folder tree, showing per-asset progress with filename, size, and cloud status
- `export --album-id <id-or-title> --out <dir> [--size <px>] [--originals]` exports either JPEG previews or original files with a progress bar showing filename, size, and cloud status; `--album-id` accepts either a PhotoKit local identifier or an album title
The bridge uses PhotoKit to:
@@ -48,7 +48,7 @@ make build
Output binary:
```bash
./bin/applephotos
./bin/photoscli
```
## Test
@@ -62,16 +62,16 @@ Tests run against a stub bridge, so they do not require real Photos access.
## Usage
```bash
./bin/applephotos albums
./bin/applephotos photos --album-id "<album-local-identifier>"
./bin/applephotos photos --album-id "Vacation"
./bin/applephotos tree
./bin/applephotos backup-all --out ./backup
./bin/applephotos backup-all --out ./backup --originals
./bin/applephotos export --album-id "<album-local-identifier>" --out ./export
./bin/applephotos export --album-id "Vacation" --out ./export
./bin/applephotos export --album-id "<album-local-identifier>" --out ./export --size 2048
./bin/applephotos export --album-id "<album-local-identifier>" --out ./export --originals
./bin/photoscli albums
./bin/photoscli photos --album-id "<album-local-identifier>"
./bin/photoscli photos --album-id "Vacation"
./bin/photoscli tree
./bin/photoscli backup-all --out ./backup
./bin/photoscli backup-all --out ./backup --originals
./bin/photoscli export --album-id "<album-local-identifier>" --out ./export
./bin/photoscli export --album-id "Vacation" --out ./export
./bin/photoscli export --album-id "<album-local-identifier>" --out ./export --size 2048
./bin/photoscli export --album-id "<album-local-identifier>" --out ./export --originals
```
### Commands
@@ -93,13 +93,13 @@ Example output:
- Requests Photos access
- If the value looks like a PhotoKit local identifier, uses it directly
- Otherwise searches album titles for a match and resolves the identifier
- Lists asset local identifiers for the given album
- Lists asset local identifiers and cloud status for the given album
Example output:
```text
1F2A.../L0/001 IMG_0001.JPG
9C4D.../L0/001 IMG_0002.JPG
1F2A.../L0/001 IMG_0001.JPG local
9C4D.../L0/001 IMG_0002.JPG cloud
```
`backup-all --out <dir> [--size <px>] [--originals]`
@@ -107,8 +107,8 @@ Example output:
- Requests Photos access
- Walks the Photos folder and album hierarchy
- Creates directories as `out/folder/album/files`
- Exports previews by default
- Exports original files when `--originals` is present
- Exports previews by default, originals when `--originals` is present
- Shows per-asset progress bar with filename, file size, and cloud/local status
- Uses `--size` only for preview export
Example layout:
@@ -128,6 +128,8 @@ backup/
- Requests Photos access
- Resolves `--album-id` by local identifier first, then by album title if not found
- Creates the output directory if needed
- Exports assets one at a time with a progress bar: `[=======---] 50% filename.jpg 1.2 MB cloud`
- Shows file size and cloud/local status for each exported asset
- Exports resized JPEG previews by default
- Exports original files when `--originals` is present
- Writes a summary like `exported 10 photos to ./export` or `exported 10 original files to ./export` to stderr
@@ -187,7 +189,9 @@ Sending `SIGINT` (Ctrl+C) or `SIGTERM` during export or backup triggers a gracef
A second signal forces an immediate exit.
- `cmd/applephotos`: CLI entrypoint, argument parsing, and album name resolution
## Architecture
- `cmd/photoscli`: CLI entrypoint, argument parsing, and album name resolution
- `internal/photos`: Go bridge interface, JSON parsing, and error mapping
- `bridge/`: Objective-C PhotoKit implementation plus a C test stub
@@ -201,6 +205,5 @@ Data passed from Objective-C to Go is serialized as JSON and unmarshaled into Go
- Preview export uses PhotoKit preview rendering, not original file export
- Original export currently writes the first PhotoKit asset resource for each asset, which may not capture every related representation for complex assets
- iCloud-backed assets may require network download during export
- Export is synchronous and has no progress output
- A second interrupt signal forces an immediate exit without waiting for the current file
- Partial export failures are not listed individually
@@ -5,7 +5,7 @@ import (
"io"
"strings"
"github.com/einand/applephotos/internal/photos"
"gitea.k3s.k0.nu/tools/photocli/internal/photos"
)
func run(args []string, stdout, stderr io.Writer, bridge photos.Bridge) int {
@@ -37,14 +37,14 @@ func run(args []string, stdout, stderr io.Writer, bridge photos.Bridge) int {
}
func usage(w io.Writer) {
fmt.Fprintln(w, `applephotos export optimized images from Apple Photos
fmt.Fprintln(w, `photoscli export optimized images from Apple Photos
Usage:
applephotos albums
applephotos photos --album-id <id>
applephotos tree
applephotos backup-all --out <dir> [--size <px>] [--originals]
applephotos export --album-id <id> --out <dir> [--size <px>] [--originals]
photoscli albums
photoscli photos --album-id <id>
photoscli tree
photoscli backup-all --out <dir> [--size <px>] [--originals]
photoscli export --album-id <id> --out <dir> [--size <px>] [--originals]
Commands:
albums List user-created albums
@@ -5,7 +5,7 @@ import (
"os/signal"
"syscall"
"github.com/einand/applephotos/internal/photos"
"gitea.k3s.k0.nu/tools/photocli/internal/photos"
)
func main() {
@@ -8,7 +8,7 @@ import (
"strings"
"testing"
"github.com/einand/applephotos/internal/photos"
"gitea.k3s.k0.nu/tools/photocli/internal/photos"
)
type mockBridge struct {
@@ -89,7 +89,7 @@ func TestRunNoArgs(t *testing.T) {
if rc != 1 {
t.Errorf("rc = %d, want 1", rc)
}
if !strings.Contains(stderr, "applephotos") {
if !strings.Contains(stderr, "photoscli") {
t.Errorf("stderr should contain usage, got: %s", stderr)
}
}
@@ -100,7 +100,7 @@ func TestRunHelp(t *testing.T) {
if rc != 0 {
t.Errorf("%s: rc = %d, want 0", cmd, rc)
}
if !strings.Contains(stderr, "applephotos") {
if !strings.Contains(stderr, "photoscli") {
t.Errorf("%s: stderr should contain usage", cmd)
}
}
+1 -1
View File
@@ -1,3 +1,3 @@
module github.com/einand/applephotos
module gitea.k3s.k0.nu/tools/photocli
go 1.22