From 8adfd32a18c1221407ff7000c23a6cb14e5363d1 Mon Sep 17 00:00:00 2001 From: GJ Compagner Date: Sun, 18 Aug 2024 10:29:40 +0200 Subject: [PATCH] Add support for -use-full-path-album-name to be able to use the full path to the file as album name/title (#444) * Add support for -use-full-path-album-name to be able to use the full path to the file as album name/title * Merge remote-tracking branch 'origin/main' into pr/giejay/444 --- browser/files/localassets.go | 1 + cmd/upload/upload.go | 15 +++++++++++- cmd/upload/upload_test.go | 46 +++++++++++++++++++++++++++++++++++- readme.md | 24 ++++++++++--------- 4 files changed, 73 insertions(+), 13 deletions(-) diff --git a/browser/files/localassets.go b/browser/files/localassets.go index 5caf630a..d903a1b0 100644 --- a/browser/files/localassets.go +++ b/browser/files/localassets.go @@ -275,6 +275,7 @@ func (la *LocalAssetBrowser) assetFromFile(fsys fs.FS, name string) (*browser.Lo if fsys, ok := fsys.(fshelper.NameFS); ok { fullPath = filepath.Join(fsys.Name(), name) } + a.Metadata.DateTaken = metadata.TakeTimeFromPath(fullPath) i, err := fs.Stat(fsys, name) diff --git a/cmd/upload/upload.go b/cmd/upload/upload.go index 8df140e2..f446ca65 100644 --- a/cmd/upload/upload.go +++ b/cmd/upload/upload.go @@ -38,6 +38,8 @@ type UpCmd struct { GooglePhotos bool // For reading Google Photos takeout files Delete bool // Delete original file after import CreateAlbumAfterFolder bool // Create albums for assets based on the parent folder or a given name + UseFullPathAsAlbumName bool // Create albums for assets based on the full path to the asset + AlbumNamePathSeparator string // Determines how multiple (sub) folders, if any, will be joined ImportIntoAlbum string // All assets will be added to this album PartnerAlbum string // Partner's assets will be added to this album Import bool // Import instead of upload @@ -119,6 +121,14 @@ func newCommand(ctx context.Context, common *cmd.SharedFlags, args []string, fsO "create-album-folder", " folder import only: Create albums for assets based on the parent folder", myflag.BoolFlagFn(&app.CreateAlbumAfterFolder, false)) + cmd.BoolFunc( + "use-full-path-album-name", + " folder import only: Use the full path towards the asset for determining the Album name", + myflag.BoolFlagFn(&app.UseFullPathAsAlbumName, false)) + cmd.StringVar(&app.AlbumNamePathSeparator, + "album-name-path-separator", + " ", + " when use-full-path-album-name = true, determines how multiple (sub) folders, if any, will be joined") cmd.BoolFunc( "google-photos", "Import GooglePhotos takeout zip files", @@ -565,7 +575,7 @@ func (app *UpCmd) manageAssetAlbum(ctx context.Context, assetID string, a *brows } app.Jnl.Record(ctx, fileevent.UploadAddToAlbum, a, a.FileName, "album", album, "reason", "option -create-album-folder") if !app.DryRun { - err := app.AddToAlbum(ctx, assetID, browser.LocalAlbum{Title: album}) + err := app.AddToAlbum(ctx, assetID, browser.LocalAlbum{Title: album, Path: a.FileName}) if err != nil { app.Jnl.Record(ctx, fileevent.Error, a, a.FileName, "error", err.Error()) } @@ -678,6 +688,9 @@ func (app *UpCmd) AddToAlbum(ctx context.Context, id string, album browser.Local title := album.Title if (app.GooglePhotos && (title == "" || app.CreateAlbumAfterFolder)) || app.UseFolderAsAlbumName { title = filepath.Base(album.Path) + } else if !app.GooglePhotos && app.UseFullPathAsAlbumName { + // full path + title = strings.Replace(filepath.Dir(album.Path), "/", app.AlbumNamePathSeparator, -1) } l, exist := app.albums[title] diff --git a/cmd/upload/upload_test.go b/cmd/upload/upload_test.go index 47fdec50..9e548008 100644 --- a/cmd/upload/upload_test.go +++ b/cmd/upload/upload_test.go @@ -466,7 +466,51 @@ func TestUpload(t *testing.T) { }, }, }, - + { + name: "folder and albums creation using full path", + args: []string{ + "-create-album-folder", + "-use-full-path-album-name", + "TEST_DATA/Takeout2", + }, + expectedAssets: []string{ + "Google Photos/Photos from 2023/PXL_20231006_063528961.jpg", + "Google Photos/Photos from 2023/PXL_20231006_063000139.jpg", + "Google Photos/Sans titre(9)/PXL_20231006_063108407.jpg", + }, + expectedAlbums: map[string][]string{ + "Google Photos Photos from 2023": { + "Google Photos/Photos from 2023/PXL_20231006_063000139.jpg", + "Google Photos/Photos from 2023/PXL_20231006_063528961.jpg", + }, + "Google Photos Sans titre(9)": { + "Google Photos/Sans titre(9)/PXL_20231006_063108407.jpg", + }, + }, + }, + { + name: "folder and albums creation using full path and custom separator", + args: []string{ + "-create-album-folder", + "-use-full-path-album-name", + "-album-name-path-separator= & ", + "TEST_DATA/Takeout2", + }, + expectedAssets: []string{ + "Google Photos/Photos from 2023/PXL_20231006_063528961.jpg", + "Google Photos/Photos from 2023/PXL_20231006_063000139.jpg", + "Google Photos/Sans titre(9)/PXL_20231006_063108407.jpg", + }, + expectedAlbums: map[string][]string{ + "Google Photos & Photos from 2023": { + "Google Photos/Photos from 2023/PXL_20231006_063000139.jpg", + "Google Photos/Photos from 2023/PXL_20231006_063528961.jpg", + }, + "Google Photos & Sans titre(9)": { + "Google Photos/Sans titre(9)/PXL_20231006_063108407.jpg", + }, + }, + }, // // { // // name: "google photo, homonyms, keep partner", // // args: []string{ diff --git a/readme.md b/readme.md index ac1e0555..e3fcc862 100644 --- a/readme.md +++ b/readme.md @@ -95,17 +95,19 @@ Use this command for uploading photos and videos from a local directory, a zippe ### Switches and options: -| **Parameter** | **Description** | **Default value** | -| ------------------------------------ | -------------------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------- | -| `-album="ALBUM NAME"` | Import assets into the Immich album `ALBUM NAME`. | | -| `-dry-run` | Preview all actions as they would be done. | `FALSE` | -| `-create-album-folder` | Generate immich albums after folder names. | `FALSE` | -| `-create-stacks` | Stack jpg/raw or bursts. | `FALSE` | -| `-stack-jpg-raw` | Control the stacking of jpg/raw photos. | `FALSE` | -| `-stack-burst` | Control the stacking bursts. | `FALSE` | -| `-select-types=".ext,.ext,.ext..."` | List of accepted extensions. | | -| `-exclude-types=".ext,.ext,.ext..."` | List of excluded extensions. | | -| `-when-no-date=FILE\|NOW` | When the date of take can't be determined, use the FILE's date or the current time NOW. | `FILE` | +| **Parameter** | **Description** | **Default value** | +|--------------------------------------|-------------------------------------------------------------------------------------------------|-------------------------------------------------------------------------------------------| +| `-album="ALBUM NAME"` | Import assets into the Immich album `ALBUM NAME`. | | +| `-dry-run` | Preview all actions as they would be done. | `FALSE` | +| `-create-album-folder` | Generate immich albums after folder names. | `FALSE` | +| `-use-full-path-album-name` | Use the full path to the file to determine the album name. | `FALSE` | +| `-album-name-path-separator` | Determines how multiple (sub) folders, if any, will be joined | ` ` | +| `-create-stacks` | Stack jpg/raw or bursts. | `FALSE` | +| `-stack-jpg-raw` | Control the stacking of jpg/raw photos. | `FALSE` | +| `-stack-burst` | Control the stacking bursts. | `FALSE` | +| `-select-types=".ext,.ext,.ext..."` | List of accepted extensions. | | +| `-exclude-types=".ext,.ext,.ext..."` | List of excluded extensions. | | +| `-when-no-date=FILE\|NOW` | When the date of take can't be determined, use the FILE's date or the current time NOW. | `FILE` | | `-exclude-files=pattern` | Ignore files based on a pattern. Case insensitive. Repeat the option for each pattern do you need. | `@eaDir/`
`@__thumb/`
`SYNOFILE_THUMB_*.*`
`Lightroom Catalog/`
`thumbnails/` | ### Date selection: