85eaa3ea37
Critical: - Replace DISPATCH_TIME_FOREVER with 120s/30s timeouts in ObjC - Log failed asset IDs and error messages in cmdExport/backupTree - Show failed count in export summaries Cleanup: - Remove legacy Bridge methods (ExportAlbumPreviews, ExportAlbumOriginals, BackupAll) - Remove legacy ObjC functions and C stub equivalents - Remove photos.go delegates (package-level pass-throughs) - Remove InterpretExportResult (only used by legacy methods) - Clean up mockBridge fields (rename Fn2 -> Fn) - Fix rc race condition in main_main.go (atomic.Int32) - Remove unused variables (_ = grandTotal, _ = sig) Design: - Fix resolveAlbumID: ListAlbums first (cheap), then direct ID - Unify Cloud type: Asset.Cloud string (was bool) - Extract shared export logic into exportAssets/exportOne - Add worker pool for parallel exports (3 workers when assets >= 4) - Fix backupTree progress bar counter and directory prefix Robustness: - Add nil checks for stringWithUTF8String: in ObjC - Log directory creation errors in ensure_directory (ObjC) Quality: - Add go vet and -race flag to Makefile test target - Add ADR for performSelector cloudIdentifier decision - Add sync comments between Go/ObjC sanitizePathComponent - Add package-level doc comment - Add tests: partial failure, skipped album, album-not-found message
62 lines
1.6 KiB
Go
62 lines
1.6 KiB
Go
package photos
|
|
|
|
import (
|
|
"encoding/json"
|
|
"fmt"
|
|
)
|
|
|
|
type Bridge interface {
|
|
RequestAccess() error
|
|
ListAlbums() ([]Album, error)
|
|
ListAssets(albumID string) ([]Asset, int, error)
|
|
ListTree() ([]CollectionNode, error)
|
|
ExportPreview(assetID, outputDir string, targetSize, index int) (ExportResult, error)
|
|
ExportOriginal(assetID, outputDir string, index int) (ExportResult, error)
|
|
Cancel()
|
|
}
|
|
|
|
func ParseAlbumsJSON(jsonStr string) ([]Album, error) {
|
|
var resp AlbumsResponse
|
|
if err := json.Unmarshal([]byte(jsonStr), &resp); err != nil {
|
|
return nil, err
|
|
}
|
|
return resp.Albums, nil
|
|
}
|
|
|
|
func ParseAssetsJSON(jsonStr string) ([]Asset, int, error) {
|
|
var errResp ErrorResponse
|
|
if err := json.Unmarshal([]byte(jsonStr), &errResp); err == nil && errResp.Error != "" {
|
|
return nil, 0, fmt.Errorf("%s", errResp.Error)
|
|
}
|
|
|
|
var resp AssetsResponse
|
|
if err := json.Unmarshal([]byte(jsonStr), &resp); err != nil {
|
|
return nil, 0, err
|
|
}
|
|
return resp.Assets, resp.Total, nil
|
|
}
|
|
|
|
func ParseTreeJSON(jsonStr string) ([]CollectionNode, error) {
|
|
var errResp ErrorResponse
|
|
if err := json.Unmarshal([]byte(jsonStr), &errResp); err == nil && errResp.Error != "" {
|
|
return nil, fmt.Errorf("%s", errResp.Error)
|
|
}
|
|
|
|
var resp TreeResponse
|
|
if err := json.Unmarshal([]byte(jsonStr), &resp); err != nil {
|
|
return nil, err
|
|
}
|
|
return resp.Collections, nil
|
|
}
|
|
|
|
func ParseExportResultJSON(jsonStr string) (ExportResult, error) {
|
|
var resp ExportResultResponse
|
|
if err := json.Unmarshal([]byte(jsonStr), &resp); err != nil {
|
|
return ExportResult{}, err
|
|
}
|
|
if resp.Error != "" {
|
|
return ExportResult{}, fmt.Errorf("%s", resp.Error)
|
|
}
|
|
return resp.ExportResult, nil
|
|
}
|