Skip to content
Open
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
7 changes: 6 additions & 1 deletion adapters/googlePhotos/googlephotos.go
Original file line number Diff line number Diff line change
Expand Up @@ -213,7 +213,7 @@ func (to *Takeout) passOneFsWalk(ctx context.Context, w fs.FS) error {
if err == nil {
switch {
case md.isAsset():
md := md.AsMetadata(fshelper.FSName(w, name), to.flags.PeopleTag) // Keep metadata
md := md.AsMetadata(fshelper.FSName(w, name), to.flags.PeopleTag, to.flags) // Keep metadata
dirCatalog.jsons[base] = md
to.log.Log().Debug("Asset JSON", "metadata", md)
to.log.Record(ctx, fileevent.DiscoveredSidecar, fshelper.FSName(w, name), "type", "asset metadata", "title", md.FileName, "date", md.DateTaken)
Expand Down Expand Up @@ -573,6 +573,11 @@ func (to *Takeout) filterOnMetadata(ctx context.Context, a *assets.Asset) fileev
a.Close()
return fileevent.DiscoveredDiscarded
}
if !to.flags.KeepSharedAlbum && a.FromSharedAlbum {
to.logMessage(ctx, fileevent.DiscoveredDiscarded, a, "discarding shared album file")
a.Close()
return fileevent.DiscoveredDiscarded
}
if !to.flags.KeepTrashed && a.Trashed {
to.logMessage(ctx, fileevent.DiscoveredDiscarded, a, "discarding trashed file")
a.Close()
Expand Down
30 changes: 22 additions & 8 deletions adapters/googlePhotos/json.go
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ type GoogleMetaData struct {
People []Person `json:"people,omitempty"` // People tags
GooglePhotosOrigin struct {
FromPartnerSharing googIsPresent `json:"fromPartnerSharing,omitempty"` // true when this is a partner's asset
FromSharedAlbum googIsPresent `json:"fromSharedAlbum,omitempty"` // true when this is from a shared album
} `json:"googlePhotosOrigin"`
}

Expand Down Expand Up @@ -78,15 +79,16 @@ func (gmd GoogleMetaData) LogValue() slog.Value {
)
}

func (gmd GoogleMetaData) AsMetadata(name fshelper.FSAndName, tagPeople bool) *assets.Metadata {
func (gmd GoogleMetaData) AsMetadata(name fshelper.FSAndName, tagPeople bool, flags *ImportFlags) *assets.Metadata {
md := assets.Metadata{
File: name,
FileName: sanitizedTitle(gmd.Title),
Description: gmd.Description,
Trashed: gmd.Trashed,
Archived: gmd.Archived,
Favorited: gmd.Favorited,
FromPartner: gmd.isPartner(),
File: name,
FileName: sanitizedTitle(gmd.Title),
Description: gmd.Description,
Trashed: gmd.Trashed,
Archived: gmd.Archived,
Favorited: gmd.Favorited,
FromPartner: gmd.isPartner(),
FromSharedAlbum: gmd.isSharedAlbum(),
}
if gmd.GeoDataExif != nil {
md.Latitude, md.Longitude = gmd.GeoDataExif.Latitude, gmd.GeoDataExif.Longitude
Expand All @@ -106,6 +108,11 @@ func (gmd GoogleMetaData) AsMetadata(name fshelper.FSAndName, tagPeople bool) *a
md.AddTag("People/" + p.Name)
}
}

if flags.SharedAlbumTag && md.FromSharedAlbum {
md.AddTag("From Shared Album")
}

return &md
}

Expand All @@ -130,6 +137,13 @@ func (gmd *GoogleMetaData) isPartner() bool {
return bool(gmd.GooglePhotosOrigin.FromPartnerSharing)
}

func (gmd *GoogleMetaData) isSharedAlbum() bool {
if gmd == nil {
return false
}
return bool(gmd.GooglePhotosOrigin.FromSharedAlbum)
}

// Key return an expected unique key for the asset
// based on the title and the timestamp
func (gmd GoogleMetaData) Key() string {
Expand Down
9 changes: 9 additions & 0 deletions adapters/googlePhotos/options.go
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,9 @@ type ImportFlags struct {
// KeepPartner determines whether to import photos from the partner's Google Photos account.
KeepPartner bool

// KeepSharedAlbum determines whether to import photos from shared albums.
KeepSharedAlbum bool

// KeepUntitled determines whether to include photos from albums without a title in the import process.
KeepUntitled bool

Expand Down Expand Up @@ -79,6 +82,10 @@ type ImportFlags struct {

// PeopleTag indicates whether to add a people tag to the imported assets.
PeopleTag bool

// SharedAlbumTag indicates whether to add \"From Shared Album\" tag.
SharedAlbumTag bool

// Timezone
TZ *time.Location
}
Expand All @@ -99,6 +106,7 @@ func (o *ImportFlags) AddFromGooglePhotosFlags(cmd *cobra.Command, parent *cobra
cmd.Flags().BoolVar(&o.KeepUntitled, "include-untitled-albums", false, "Include photos from albums without a title in the import process")
cmd.Flags().BoolVarP(&o.KeepTrashed, "include-trashed", "t", false, "Import photos that are marked as trashed in Google Photos")
cmd.Flags().BoolVarP(&o.KeepPartner, "include-partner", "p", true, "Import photos from your partner's Google Photos account")
cmd.Flags().BoolVar(&o.KeepSharedAlbum, "include-shared-album", true, "Import photos from shared albums in Google Photos")
cmd.Flags().StringVar(&o.PartnerSharedAlbum, "partner-shared-album", "", "Add partner's photo to the specified album name")
cmd.Flags().BoolVarP(&o.KeepArchived, "include-archived", "a", true, "Import archived Google Photos")
cmd.Flags().BoolVarP(&o.KeepJSONLess, "include-unmatched", "u", false, "Import photos that do not have a matching JSON file in the takeout")
Expand All @@ -107,6 +115,7 @@ func (o *ImportFlags) AddFromGooglePhotosFlags(cmd *cobra.Command, parent *cobra
cmd.Flags().BoolVar(&o.SessionTag, "session-tag", false, "Tag uploaded photos with a tag \"{immich-go}/YYYY-MM-DD HH-MM-SS\"")
cmd.Flags().BoolVar(&o.TakeoutTag, "takeout-tag", true, "Tag uploaded photos with a tag \"{takeout}/takeout-YYYYMMDDTHHMMSSZ\"")
cmd.Flags().BoolVar(&o.PeopleTag, "people-tag", true, "Tag uploaded photos with tags \"people/name\" found in the JSON file")
cmd.Flags().BoolVar(&o.SharedAlbumTag, "shared-album-tag", true, "Tag photos from shared albums with \"From Shared Album\"")
cliflags.AddInclusionFlags(cmd, &o.InclusionFlags)

// exif.AddExifToolFlags(cmd, &o.ExifToolFlags)
Expand Down
19 changes: 11 additions & 8 deletions internal/assets/asset.go
Original file line number Diff line number Diff line change
Expand Up @@ -39,14 +39,15 @@ type Asset struct {
FileSize int // File size in bytes

// Metadata for the process and the upload to Immich
CaptureDate time.Time // Date of the capture
Trashed bool // The asset is trashed
Archived bool // The asset is archived
FromPartner bool // the asset comes from a partner
Favorite bool // the asset is marked as favorite
Rating int // the asset is marked with stars
Albums []Album // List of albums the asset is in
Tags []Tag // List of tags the asset is tagged with
CaptureDate time.Time // Date of the capture
Trashed bool // The asset is trashed
Archived bool // The asset is archived
FromPartner bool // the asset comes from a partner
FromSharedAlbum bool // the asset comes from a shared album
Favorite bool // the asset is marked as favorite
Rating int // the asset is marked with stars
Albums []Album // List of albums the asset is in
Tags []Tag // List of tags the asset is tagged with

// Information inferred from the original file name
NameInfo
Expand Down Expand Up @@ -101,6 +102,7 @@ func (a *Asset) UseMetadata(md *Metadata) *Metadata {
a.Longitude = md.Longitude
a.CaptureDate = md.DateTaken
a.FromPartner = md.FromPartner
a.FromSharedAlbum = md.FromSharedAlbum
a.Trashed = md.Trashed
a.Archived = md.Archived
a.Favorite = md.Favorited
Expand All @@ -127,6 +129,7 @@ func (a Asset) LogValue() slog.Value {
slog.Bool("Trashed", a.Trashed),
slog.Bool("Archived", a.Archived),
slog.Bool("FromPartner", a.FromPartner),
slog.Bool("FromSharedAlbum", a.FromSharedAlbum),
slog.Bool("Favorite", a.Favorite),
slog.Int("Stars", a.Rating),
slog.String("Latitude", fmt.Sprintf("%.0f.xxxxx", a.Latitude)),
Expand Down
30 changes: 16 additions & 14 deletions internal/assets/metadata.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,20 +11,21 @@ import (
)

type Metadata struct {
File fshelper.FSAndName `json:"-"` // File name and file system that holds the metadata. Could be empty
FileName string `json:"fileName,omitempty"` // File name as presented to users
Latitude float64 `json:"latitude,omitempty"` // GPS
Longitude float64 `json:"longitude,omitempty"` // GPS
FileDate time.Time `json:"fileDate,omitzero"` // Date of the file
DateTaken time.Time `json:"dateTaken,omitzero"` // Date of exposure
Description string `json:"description,omitempty"` // Long description
Albums []Album `json:"albums,omitempty"` // Used to list albums that contain the file
Tags []Tag `json:"tags,omitempty"` // Used to list tags
Rating byte `json:"rating,omitempty"` // 0 to 5
Trashed bool `json:"trashed,omitempty"` // Flag to indicate if the image has been trashed
Archived bool `json:"archived,omitempty"` // Flag to indicate if the image has been archived
Favorited bool `json:"favorited,omitempty"` // Flag to indicate if the image has been favorited
FromPartner bool `json:"fromPartner,omitempty"` // Flag to indicate if the image is from a partner
File fshelper.FSAndName `json:"-"` // File name and file system that holds the metadata. Could be empty
FileName string `json:"fileName,omitempty"` // File name as presented to users
Latitude float64 `json:"latitude,omitempty"` // GPS
Longitude float64 `json:"longitude,omitempty"` // GPS
FileDate time.Time `json:"fileDate,omitzero"` // Date of the file
DateTaken time.Time `json:"dateTaken,omitzero"` // Date of exposure
Description string `json:"description,omitempty"` // Long description
Albums []Album `json:"albums,omitempty"` // Used to list albums that contain the file
Tags []Tag `json:"tags,omitempty"` // Used to list tags
Rating byte `json:"rating,omitempty"` // 0 to 5
Trashed bool `json:"trashed,omitempty"` // Flag to indicate if the image has been trashed
Archived bool `json:"archived,omitempty"` // Flag to indicate if the image has been archived
Favorited bool `json:"favorited,omitempty"` // Flag to indicate if the image has been favorited
FromPartner bool `json:"fromPartner,omitempty"` // Flag to indicate if the image is from a partner
FromSharedAlbum bool `json:"fromSharedAlbum,omitempty"` // Flag to indicate if the image is from a shared album
}

func (m Metadata) LogValue() slog.Value {
Expand All @@ -46,6 +47,7 @@ func (m Metadata) LogValue() slog.Value {
slog.Bool("archived", m.Archived),
slog.Bool("favorited", m.Favorited),
slog.Bool("fromPartner", m.FromPartner),
slog.Bool("fromSharedAlbum", m.FromSharedAlbum),
slog.Any("albums", m.Albums),
slog.Any("tags", m.Tags),
)
Expand Down
2 changes: 2 additions & 0 deletions readme.md
Original file line number Diff line number Diff line change
Expand Up @@ -401,6 +401,7 @@ The **from-google-photos** sub-command processes a Google Photos takeout archive
| --include-extensions | `all` | Comma-separated list of extension to include. (e.g. .jpg, .heic) |
| --include-type | `all` | Single file type to include. (`VIDEO` or `IMAGE`) |
| -p, --include-partner | `TRUE` | Import photos from your partner's Google Photos account |
| --include-shared-album | `TRUE` | Import photos from others in shared albums in Google Photos |
| -t, --include-trashed | `FALSE` | Import photos that are marked as trashed in Google Photos |
| -u, --include-unmatched | `FALSE` | Import photos that do not have a matching JSON file in the takeout |
| --include-untitled-albums | `FALSE` | Include photos from albums without a title in the import process |
Expand All @@ -414,6 +415,7 @@ The **from-google-photos** sub-command processes a Google Photos takeout archive
| --tag strings | | Add tags to the imported assets. Can be specified multiple times. Hierarchy is supported using a / separator (e.g. 'tag1/subtag1') |
| --takeout-tag | `TRUE` | Tag uploaded photos with a tag "{takeout}/takeout-YYYYMMDDTHHMMSSZ" |
| --people-tag | `TRUE` | Tag uploaded photos with tags \"people/name\" found in the JSON file |
| --shared-album-tag | `TRUE` | Tag photos from others in shared albums with \"From Shared Album\". |

## Google Photos Best Practices:

Expand Down