diff --git a/browser/gp/googlephotos.go b/browser/gp/googlephotos.go index c3162a29..9a936ed4 100644 --- a/browser/gp/googlephotos.go +++ b/browser/gp/googlephotos.go @@ -2,7 +2,6 @@ package gp import ( "context" - "fmt" "io/fs" "path" "path/filepath" @@ -20,55 +19,38 @@ import ( ) type Takeout struct { - fsyss []fs.FS - catalogs dirCatalog // file catalogs by directory in the set of the all takeout parts - jsonByYear map[jsonKey]*GoogleMetaData // assets by year of capture and base name - uploaded map[fileKey]any // track files already uploaded - albums map[string]browser.LocalAlbum // tack album names by folder - log *fileevent.Recorder - sm immich.SupportedMedia - banned namematcher.List // Banned files + fsyss []fs.FS + catalogs map[string]directoryCatalog // file catalogs by directory in the set of the all takeout parts + albums map[string]browser.LocalAlbum // track album names by folder + log *fileevent.Recorder + sm immich.SupportedMedia + + banned namematcher.List // Banned files + acceptMissingJSON bool } -// dirCatalog collects all directory catalogs -type dirCatalog map[string]directoryCatalog // by directory in the walker - // directoryCatalog captures all files in a given directory type directoryCatalog struct { - unMatchedFiles map[string]fileInfo // map of fileInfo by base name - matchedFiles map[string]fileInfo // map of fileInfo by base name + jsons map[string]*GoogleMetaData // JSONs in the catalog by base name + unMatchedFiles map[string]*assetFile // files to be matched map by base name + matchedFiles map[string]*assetFile // files matched by base name } -// fileInfo keep information collected during pass one -type fileInfo struct { +// assetFile keep information collected during pass one +type assetFile struct { fsys fs.FS // Remember in which part of the archive the the file base string // Remember the original file name length int // file length in bytes - count int // Track duplicates md *GoogleMetaData // will point to the associated metadata } -// fileKey is the key of the uploaded files map -// GP can't have duplicate JSON name in the same year. -type fileKey struct { - base string - length int - year int -} - -// jsonKey allow to map jsons by base name and year of capture -type jsonKey struct { - name string - year int -} - func NewTakeout(ctx context.Context, l *fileevent.Recorder, sm immich.SupportedMedia, fsyss ...fs.FS) (*Takeout, error) { to := Takeout{ - fsyss: fsyss, - jsonByYear: map[jsonKey]*GoogleMetaData{}, - albums: map[string]browser.LocalAlbum{}, - log: l, - sm: sm, + fsyss: fsyss, + catalogs: map[string]directoryCatalog{}, + albums: map[string]browser.LocalAlbum{}, + log: l, + sm: sm, } return &to, nil @@ -79,11 +61,15 @@ func (to *Takeout) SetBannedFiles(banned namematcher.List) *Takeout { return to } +func (to *Takeout) SetAcceptMissingJSON(flag bool) *Takeout { + to.acceptMissingJSON = flag + return to +} + // Prepare scans all files in all walker to build the file catalog of the archive // metadata files content is read and kept func (to *Takeout) Prepare(ctx context.Context) error { - to.catalogs = dirCatalog{} for _, w := range to.fsyss { err := to.passOneFsWalk(ctx, w) if err != nil { @@ -113,15 +99,20 @@ func (to *Takeout) passOneFsWalk(ctx context.Context, w fs.FS) error { dir = strings.TrimSuffix(dir, "/") ext := strings.ToLower(path.Ext(base)) - dirCatalog := to.catalogs[dir] - if dirCatalog.unMatchedFiles == nil { - dirCatalog.unMatchedFiles = map[string]fileInfo{} + dirCatalog, ok := to.catalogs[dir] + if !ok { + dirCatalog.jsons = map[string]*GoogleMetaData{} + dirCatalog.unMatchedFiles = map[string]*assetFile{} + dirCatalog.matchedFiles = map[string]*assetFile{} } - if dirCatalog.matchedFiles == nil { - dirCatalog.matchedFiles = map[string]fileInfo{} + if _, ok := dirCatalog.unMatchedFiles[base]; ok { + // to.log.Record(ctx, fileevent.AnalysisLocalDuplicate, nil, name) + return nil } + finfo, err := d.Info() if err != nil { + to.log.Record(ctx, fileevent.Error, nil, name, "error", err.Error()) return err } switch ext { @@ -130,7 +121,8 @@ func (to *Takeout) passOneFsWalk(ctx context.Context, w fs.FS) error { if err == nil { switch { case md.isAsset(): - to.addJSON(dir, base, md) + md.foundInPaths = append(md.foundInPaths, dir) + dirCatalog.jsons[base] = md to.log.Record(ctx, fileevent.DiscoveredSidecar, nil, name, "type", "asset metadata", "title", md.Title) case md.isAlbum(): a := to.albums[dir] @@ -172,15 +164,10 @@ func (to *Takeout) passOneFsWalk(ctx context.Context, w fs.FS) error { return nil } - fi := dirCatalog.unMatchedFiles[base] - fi.base = base - fi.fsys = w - fi.length = int(finfo.Size()) - fi.count++ - dirCatalog.unMatchedFiles[base] = fi - if fi.count > 1 { - // #380 not all GP duplicates are detected correctly, counters are wrong - to.log.Record(ctx, fileevent.AnalysisLocalDuplicate, nil, name) + dirCatalog.unMatchedFiles[base] = &assetFile{ + fsys: w, + base: base, + length: int(finfo.Size()), } } to.catalogs[dir] = dirCatalog @@ -190,36 +177,6 @@ func (to *Takeout) passOneFsWalk(ctx context.Context, w fs.FS) error { return err } -// addJSON stores metadata and all paths where the combo base+year has been found -func (to *Takeout) addJSON(dir, base string, md *GoogleMetaData) { - k := jsonKey{ - name: base, - year: md.PhotoTakenTime.Time().Year(), - } - - if mdPresent, ok := to.jsonByYear[k]; ok { - md = mdPresent - } - md.foundInPaths = append(md.foundInPaths, dir) - to.jsonByYear[k] = md -} - -type matcherFn func(jsonName string, fileName string, sm immich.SupportedMedia) bool - -// matchers is a list of matcherFn from the most likely to be used to the least one -var matchers = []struct { - name string - fn matcherFn -}{ - {name: "normalMatch", fn: normalMatch}, - {name: "livePhotoMatch", fn: livePhotoMatch}, - {name: "matchWithOneCharOmitted", fn: matchWithOneCharOmitted}, - {name: "matchVeryLongNameWithNumber", fn: matchVeryLongNameWithNumber}, - {name: "matchDuplicateInYear", fn: matchDuplicateInYear}, - {name: "matchEditedName", fn: matchEditedName}, - {name: "matchForgottenDuplicates", fn: matchForgottenDuplicates}, -} - // solvePuzzle prepares metadata with information collected during pass one for each accepted files // // JSON files give important information about the relative photos / movies: @@ -228,7 +185,9 @@ var matchers = []struct { // - The GPS coordinates (will be useful in a future release) // // Each JSON is checked. JSON is duplicated in albums folder. -// Associated files with the JSON can be found in the JSON's folder, or in the Year photos. +// --Associated files with the JSON can be found in the JSON's folder, or in the Year photos.-- +// ++JSON and files are located in the same folder +/// // Once associated and sent to the main program, files are tagged for not been associated with an other one JSON. // Association is done with the help of a set of matcher functions. Each one implement a rule // @@ -241,62 +200,62 @@ var matchers = []struct { // - of course those rules are likely to collide. They have to be applied from the most common to the least one. // - sometimes the file isn't in the same folder than the json... It can be found in Year's photos folder // -// The duplicates files (same name, same length in bytes) found in the local source are discarded before been presented to the immich server. +// --The duplicates files (same name, same length in bytes) found in the local source are discarded before been presented to the immich server. +// ++ Duplicates are presented to the next layer to allow the album handling // +// To solve the puzzle, each directory is checked with all matchers in the order of the most common to the least. -func (to *Takeout) solvePuzzle(ctx context.Context) error { - jsonKeys := gen.MapKeys(to.jsonByYear) - sort.Slice(jsonKeys, func(i, j int) bool { - yd := jsonKeys[i].year - jsonKeys[j].year - switch { - case yd < 0: - return true - case yd > 0: - return false - } - return jsonKeys[i].name < jsonKeys[j].name - }) +type matcherFn func(jsonName string, fileName string, sm immich.SupportedMedia) bool - // For the most common matcher to the least, - for _, matcher := range matchers { - // Check files that match each json files - for _, k := range jsonKeys { - md := to.jsonByYear[k] - - // list of paths where to search the assets: paths where this json has been found + year path in all of the walkers - paths := map[string]any{} - paths[path.Join(path.Dir(md.foundInPaths[0]), fmt.Sprintf("Photos from %d", md.PhotoTakenTime.Time().Year()))] = nil - for _, d := range md.foundInPaths { - paths[d] = nil - } - for d := range paths { - l := to.catalogs[d] - for f := range l.unMatchedFiles { +// matchers is a list of matcherFn from the most likely to be used to the least one +var matchers = []struct { + name string + fn matcherFn +}{ + {name: "normalMatch", fn: normalMatch}, + {name: "livePhotoMatch", fn: livePhotoMatch}, + {name: "matchWithOneCharOmitted", fn: matchWithOneCharOmitted}, + {name: "matchVeryLongNameWithNumber", fn: matchVeryLongNameWithNumber}, + {name: "matchDuplicateInYear", fn: matchDuplicateInYear}, + {name: "matchEditedName", fn: matchEditedName}, + {name: "matchForgottenDuplicates", fn: matchForgottenDuplicates}, +} + +func (to *Takeout) solvePuzzle(ctx context.Context) error { + dirs := gen.MapKeys(to.catalogs) + sort.Strings(dirs) + for _, dir := range dirs { + cat := to.catalogs[dir] + jsons := gen.MapKeys(cat.jsons) + sort.Strings(jsons) + for _, matcher := range matchers { + for _, json := range jsons { + md := cat.jsons[json] + for f := range cat.unMatchedFiles { select { case <-ctx.Done(): return ctx.Err() default: - if matcher.fn(k.name, f, to.sm) { - i := l.unMatchedFiles[f] + if matcher.fn(json, f, to.sm) { + i := cat.unMatchedFiles[f] i.md = md - l.matchedFiles[f] = i - to.log.Record(ctx, fileevent.AnalysisAssociatedMetadata, l.unMatchedFiles[f], filepath.Join(d, f), "json", k.name, "year", k.year, "size", i.length, "matcher", matcher.name) - delete(l.unMatchedFiles, f) + cat.matchedFiles[f] = i + to.log.Record(ctx, fileevent.AnalysisAssociatedMetadata, cat.unMatchedFiles[f], filepath.Join(dir, f), "json", json, "size", i.length, "matcher", matcher.name) + delete(cat.unMatchedFiles, f) } } } - to.catalogs[d] = l } } - } - - paths := gen.MapKeys(to.catalogs) - sort.Strings(paths) - for _, p := range paths { - files := gen.MapKeys(to.catalogs[p].unMatchedFiles) + to.catalogs[dir] = cat + files := gen.MapKeys(cat.unMatchedFiles) sort.Strings(files) for _, f := range files { - to.log.Record(ctx, fileevent.AnalysisMissingAssociatedMetadata, to.catalogs[p].unMatchedFiles[f], filepath.Join(p, f)) + to.log.Record(ctx, fileevent.AnalysisMissingAssociatedMetadata, f, filepath.Join(dir, f)) + if to.acceptMissingJSON { + cat.matchedFiles[f] = cat.unMatchedFiles[f] + delete(cat.unMatchedFiles, f) + } } } return nil @@ -335,21 +294,24 @@ func livePhotoMatch(jsonName string, fileName string, sm immich.SupportedMedia) // PXL_20230809_203449253.LONG_EXPOSURE-02.ORIGIN.json // PXL_20230809_203449253.LONG_EXPOSURE-02.ORIGINA.jpg // -// 05yqt21kruxwwlhhgrwrdyb6chhwszi9bqmzu16w0 2.jp.json +// 05yqt21kruxwwlhhgrwrdyb6chhwszi9bqmzu16w0 2.jp.json <-- match also with LivePhoto matcher // 05yqt21kruxwwlhhgrwrdyb6chhwszi9bqmzu16w0 2.jpg // // 😀😃😄😁😆😅😂🤣🥲☺️😊😇🙂🙃😉😌😍🥰😘😗😙😚😋.json // 😀😃😄😁😆😅😂🤣🥲☺️😊😇🙂🙃😉😌😍🥰😘😗😙😚😋😛.jpg func matchWithOneCharOmitted(jsonName string, fileName string, sm immich.SupportedMedia) bool { - base := strings.TrimSuffix(jsonName, path.Ext(jsonName)) - if strings.HasPrefix(fileName, base) { - if t := sm.TypeFromExt(path.Ext(base)); t == immich.TypeImage || t == immich.TypeVideo { - // Trim only if the EXT is known extension, and not .COVER or .ORIGINAL - base = strings.TrimSuffix(base, path.Ext(base)) - } - fileName = strings.TrimSuffix(fileName, path.Ext(fileName)) - a, b := utf8.RuneCountInString(fileName), utf8.RuneCountInString(base) + baseJSON := strings.TrimSuffix(jsonName, path.Ext(jsonName)) + ext := path.Ext(baseJSON) + if sm.IsExtensionPrefix(ext) { + baseJSON = strings.TrimSuffix(baseJSON, ext) + } + fileName = strings.TrimSuffix(fileName, path.Ext(fileName)) + if fileName == baseJSON { + return true + } + if strings.HasPrefix(fileName, baseJSON) { + a, b := utf8.RuneCountInString(fileName), utf8.RuneCountInString(baseJSON) if a-b <= 1 { return true } @@ -387,23 +349,72 @@ func matchVeryLongNameWithNumber(jsonName string, fileName string, sm immich.Sup // // IMG_3479.JPG(2).json // IMG_3479(2).JPG +// + +// Fast implementation, but does't work with live photos func matchDuplicateInYear(jsonName string, fileName string, sm immich.SupportedMedia) bool { jsonName = strings.TrimSuffix(jsonName, path.Ext(jsonName)) p1JSON := strings.Index(jsonName, "(") if p1JSON < 1 { return false } + p1File := strings.Index(fileName, "(") + if p1File < 0 { + return false + } + jsonExt := path.Ext(jsonName[:p1JSON]) + p2JSON := strings.Index(jsonName, ")") if p2JSON < 0 || p2JSON != len(jsonName)-1 { return false } - num := jsonName[p1JSON:] - jsonName = strings.TrimSuffix(jsonName, num) - ext := path.Ext(jsonName) - jsonName = strings.TrimSuffix(jsonName, ext) + num + ext - return jsonName == fileName + p2File := strings.Index(fileName, ")") + if p2File < 0 || p2File < p1File { + return false + } + + fileExt := path.Ext(fileName) + + if fileExt != jsonExt { + return false + } + + jsonBase := strings.TrimSuffix(jsonName[:p1JSON], path.Ext(jsonName[:p1JSON])) + + if jsonBase != fileName[:p1File] { + return false + } + + if fileName[p1File+1:p2File] != jsonName[p1JSON+1:p2JSON] { + return false + } + + return true +} + +/* +// Regexp implementation, work with live photos, 10 times slower +var ( + reDupInYearJSON = regexp.MustCompile(`(.*)\.(.{2,4})\((\d+)\)\..{2,4}$`) + reDupInYearFile = regexp.MustCompile(`(.*)\((\d+)\)\..{2,4}$`) +) + +func matchDuplicateInYear(jsonName string, fileName string, sm immich.SupportedMedia) bool { + mFile := reDupInYearFile.FindStringSubmatch(fileName) + if len(mFile) < 3 { + return false + } + mJSON := reDupInYearJSON.FindStringSubmatch(jsonName) + if len(mJSON) < 4 { + return false + } + if mFile[1] == mJSON[1] && mFile[2] == mJSON[3] { + return true + } + return false } +*/ // matchEditedName // PXL_20220405_090123740.PORTRAIT.jpg.json @@ -426,7 +437,7 @@ func matchEditedName(jsonName string, fileName string, sm immich.SupportedMedia) // TODO: This one interferes with matchVeryLongNameWithNumber // matchForgottenDuplicates -// original_1d4caa6f-16c6-4c3d-901b-9387de10e528_.json +// "original_1d4caa6f-16c6-4c3d-901b-9387de10e528_.json" // original_1d4caa6f-16c6-4c3d-901b-9387de10e528_P.jpg // original_1d4caa6f-16c6-4c3d-901b-9387de10e528_P(1).jpg @@ -448,12 +459,13 @@ func matchForgottenDuplicates(jsonName string, fileName string, sm immich.Suppor // each file net yet sent to immich is sent with associated metadata func (to *Takeout) Browse(ctx context.Context) chan *browser.LocalAssetFile { - to.uploaded = map[fileKey]any{} assetChan := make(chan *browser.LocalAssetFile) go func() { defer close(assetChan) - for dir := range to.catalogs { + dirs := gen.MapKeys(to.catalogs) + sort.Strings(dirs) + for _, dir := range dirs { if len(to.catalogs[dir].matchedFiles) > 0 { err := to.passTwo(ctx, dir, assetChan) if err != nil { @@ -465,31 +477,57 @@ func (to *Takeout) Browse(ctx context.Context) chan *browser.LocalAssetFile { return assetChan } +// detect livephotos and motion pictures +// 1. get all pictures +// 2. scan vidoes, if a picture matches, this is a live photo func (to *Takeout) passTwo(ctx context.Context, dir string, assetChan chan *browser.LocalAssetFile) error { catalog := to.catalogs[dir] linkedFiles := map[string]struct { - video fileInfo - image fileInfo + video *assetFile + image *assetFile }{} - // detects couples image + video, likely been a motion picture + // Scan pictures for _, f := range gen.MapKeys(catalog.matchedFiles) { ext := path.Ext(f) - base := strings.TrimSuffix(f, ext) - ext2 := path.Ext(base) - if to.sm.IsMedia(ext2) { - base = strings.TrimSuffix(base, ext2) + if to.sm.TypeFromExt(ext) == immich.TypeImage { + linked := linkedFiles[f] + linked.image = catalog.matchedFiles[f] + linkedFiles[f] = linked } + } - linked := linkedFiles[base] - switch to.sm.TypeFromExt(ext) { - case immich.TypeVideo: + // Scan videos +nextVideo: + for _, f := range gen.MapKeys(catalog.matchedFiles) { + ext := path.Ext(f) + if to.sm.TypeFromExt(ext) == immich.TypeVideo { + name := strings.TrimSuffix(f, ext) + for i, linked := range linkedFiles { + if linked.image == nil { + continue + } + if linked.image != nil && linked.video != nil { + continue + } + p := linked.image.base + ext := path.Ext(p) + p = strings.TrimSuffix(p, ext) + ext = path.Ext(p) + if strings.ToUpper(ext) == ".MP" { + p = strings.TrimSuffix(p, ext) + } + if p == name { + linked.video = catalog.matchedFiles[f] + linkedFiles[i] = linked + continue nextVideo + } + } + linked := linkedFiles[f] linked.video = catalog.matchedFiles[f] - case immich.TypeImage: - linked.image = catalog.matchedFiles[f] + linkedFiles[f] = linked } - linkedFiles[base] = linked } for _, base := range gen.MapKeys(linkedFiles) { @@ -498,14 +536,14 @@ func (to *Takeout) passTwo(ctx context.Context, dir string, assetChan chan *brow linked := linkedFiles[base] - if linked.image.md != nil { - a, err = to.googleMDToAsset(linked.image.md, linked.image.fsys, path.Join(dir, linked.image.base)) + if linked.image != nil { + a, err = to.makeAsset(linked.image.md, linked.image.fsys, path.Join(dir, linked.image.base)) if err != nil { to.log.Record(ctx, fileevent.Error, nil, path.Join(dir, linked.image.base), "error", err.Error()) continue } - if linked.video.md != nil { - i, err := to.googleMDToAsset(linked.video.md, linked.video.fsys, path.Join(dir, linked.video.base)) + if linked.video != nil { + i, err := to.makeAsset(linked.video.md, linked.video.fsys, path.Join(dir, linked.video.base)) if err != nil { to.log.Record(ctx, fileevent.Error, nil, path.Join(dir, linked.video.base), "error", err.Error()) } else { @@ -513,90 +551,85 @@ func (to *Takeout) passTwo(ctx context.Context, dir string, assetChan chan *brow } } } else { - a, err = to.googleMDToAsset(linked.video.md, linked.video.fsys, path.Join(dir, linked.video.base)) + a, err = to.makeAsset(linked.video.md, linked.video.fsys, path.Join(dir, linked.video.base)) if err != nil { to.log.Record(ctx, fileevent.Error, nil, path.Join(dir, linked.video.base), "error", err.Error()) continue } } - select { case <-ctx.Done(): return ctx.Err() default: - fk := fileKey{ - base: filepath.Base(a.FileName), - length: a.FileSize, - year: a.Metadata.DateTaken.Year(), - } - if _, found := to.uploaded[fk]; !found { - assetChan <- a - to.uploaded[fk] = nil - } else { - to.log.Record(ctx, fileevent.AnalysisLocalDuplicate, nil, a.FileName, "title", a.Title) - if a.LivePhoto != nil { - to.log.Record(ctx, fileevent.AnalysisLocalDuplicate, nil, a.LivePhoto.FileName, "title", a.LivePhoto.Title) - } - } + assetChan <- a } } return nil } -// googleMDToAsset makes a localAssetFile based on the google metadata -func (to *Takeout) googleMDToAsset(md *GoogleMetaData, fsys fs.FS, name string) (*browser.LocalAssetFile, error) { - // Change file's title with the asset's title and the actual file's extension - title := md.Title - titleExt := path.Ext(title) - fileExt := path.Ext(name) - if titleExt != fileExt { - title = strings.TrimSuffix(title, titleExt) - titleExt = path.Ext(title) - if titleExt != fileExt { - title = strings.TrimSuffix(title, titleExt) + fileExt - } - } - +// makeAsset makes a localAssetFile based on the google metadata +func (to *Takeout) makeAsset(md *GoogleMetaData, fsys fs.FS, name string) (*browser.LocalAssetFile, error) { i, err := fs.Stat(fsys, name) if err != nil { return nil, err } + a := browser.LocalAssetFile{ - FileName: name, - FileSize: int(i.Size()), - Title: title, - Archived: md.Archived, - FromPartner: md.isPartner(), - Trashed: md.Trashed, - Favorite: md.Favorited, - - FSys: fsys, + FileName: name, + FileSize: int(i.Size()), + Title: path.Base(name), + FSys: fsys, } - // Prepare sidecar data to force Immich with Google metadata - sidecar := metadata.Metadata{ - Description: md.Description, - DateTaken: md.PhotoTakenTime.Time(), - } - if md.GeoDataExif.Latitude != 0 || md.GeoDataExif.Longitude != 0 { - sidecar.Latitude = md.GeoDataExif.Latitude - sidecar.Longitude = md.GeoDataExif.Longitude - } - if md.GeoData.Latitude != 0 || md.GeoData.Longitude != 0 { - sidecar.Latitude = md.GeoData.Latitude - sidecar.Longitude = md.GeoData.Longitude + if album, ok := to.albums[path.Dir(name)]; ok { + a.Albums = append(a.Albums, album) } - for _, p := range md.foundInPaths { - if album, exists := to.albums[p]; exists { - if (album.Latitude != 0 || album.Longitude != 0) && (sidecar.Latitude == 0 && sidecar.Longitude == 0) { - sidecar.Latitude = album.Latitude - sidecar.Longitude = album.Longitude + if md != nil { + // Change file's title with the asset's title and the actual file's extension + title := md.Title + titleExt := path.Ext(title) + fileExt := path.Ext(name) + + if titleExt != fileExt { + title = strings.TrimSuffix(title, titleExt) + titleExt = path.Ext(title) + if titleExt != fileExt { + title = strings.TrimSuffix(title, titleExt) + fileExt + } + } + a.Title = title + a.Archived = md.Archived + a.FromPartner = md.isPartner() + a.Trashed = md.Trashed + a.Favorite = md.Favorited + + // Prepare sidecar data to force Immich with Google metadata + + sidecar := metadata.Metadata{ + Description: md.Description, + DateTaken: md.PhotoTakenTime.Time(), + } + + if md.GeoDataExif.Latitude != 0 || md.GeoDataExif.Longitude != 0 { + sidecar.Latitude = md.GeoDataExif.Latitude + sidecar.Longitude = md.GeoDataExif.Longitude + } + + if md.GeoData.Latitude != 0 || md.GeoData.Longitude != 0 { + sidecar.Latitude = md.GeoData.Latitude + sidecar.Longitude = md.GeoData.Longitude + } + for _, p := range md.foundInPaths { + if album, exists := to.albums[p]; exists { + if (album.Latitude != 0 || album.Longitude != 0) && (sidecar.Latitude == 0 && sidecar.Longitude == 0) { + sidecar.Latitude = album.Latitude + sidecar.Longitude = album.Longitude + } } - a.Albums = append(a.Albums, album) } + a.Metadata = sidecar } - a.Metadata = sidecar return &a, nil } diff --git a/browser/gp/googlephotos_test.go b/browser/gp/googlephotos_test.go index ef883290..3c467a82 100644 --- a/browser/gp/googlephotos_test.go +++ b/browser/gp/googlephotos_test.go @@ -6,37 +6,94 @@ import ( "github.com/simulot/immich-go/immich" ) -func Test_matchEditedName(t *testing.T) { +func Test_matchers(t *testing.T) { tests := []struct { jsonName string fileName string - want bool + want string }{ + { + jsonName: "PXL_20211013_220651983.jpg.json", + fileName: "PXL_20211013_220651983.jpg", + want: "normalMatch", + }, { jsonName: "PXL_20220405_090123740.PORTRAIT.jpg.json", fileName: "PXL_20220405_090123740.PORTRAIT-modifié.jpg", - want: true, + want: "matchEditedName", }, { jsonName: "PXL_20220405_090123740.PORTRAIT.jpg.json", fileName: "PXL_20220405_100123740.PORTRAIT-modifié.jpg", - want: false, + want: "", }, { jsonName: "DSC_0238.JPG.json", fileName: "DSC_0238.JPG", - want: true, + want: "normalMatch", + }, + { + jsonName: "DSC_0238.JPG(1).json", + fileName: "DSC_0238(1).JPG", + want: "matchDuplicateInYear", + }, + { + jsonName: "IMG_2710.HEIC(1).json", + fileName: "IMG_2710(1).HEIC", + want: "matchDuplicateInYear", + }, + { + jsonName: "PXL_20231118_035751175.MP.jpg.json", + fileName: "PXL_20231118_035751175.MP.jpg", + want: "normalMatch", + }, + { + jsonName: "PXL_20231118_035751175.MP.jpg.json", + fileName: "PXL_20231118_035751175.MP", + want: "livePhotoMatch", + }, + { + jsonName: "PXL_20230809_203449253.LONG_EXPOSURE-02.ORIGIN.json", + fileName: "PXL_20230809_203449253.LONG_EXPOSURE-02.ORIGINA.jpg", + want: "matchWithOneCharOmitted", + }, + { + jsonName: "05yqt21kruxwwlhhgrwrdyb6chhwszi9bqmzu16w0 2.jp.json", + fileName: "05yqt21kruxwwlhhgrwrdyb6chhwszi9bqmzu16w0 2.jpg", + want: "livePhotoMatch", + }, + { + jsonName: "😀😃😄😁😆😅😂🤣🥲☺️😊😇🙂🙃😉😌😍🥰😘😗😙😚😋.json", + fileName: "😀😃😄😁😆😅😂🤣🥲☺️😊😇🙂🙃😉😌😍🥰😘😗😙😚😋😛.jpg", + want: "matchWithOneCharOmitted", + }, + { + jsonName: "Backyard_ceremony_wedding_photography_xxxxxxx_(494).json", + fileName: "Backyard_ceremony_wedding_photography_xxxxxxx_m(494).jpg", + want: "matchVeryLongNameWithNumber", + }, + { + jsonName: "original_1d4caa6f-16c6-4c3d-901b-9387de10e528_.json", + fileName: "original_1d4caa6f-16c6-4c3d-901b-9387de10e528_P.jpg", + want: "matchWithOneCharOmitted", + }, + { + jsonName: "original_1d4caa6f-16c6-4c3d-901b-9387de10e528_.json", + fileName: "original_1d4caa6f-16c6-4c3d-901b-9387de10e528_P(1).jpg", + want: "matchForgottenDuplicates", }, - // { - // jsonName: "DSC_0238.JPG.json", - // fileName: "DSC_0238(1).JPG", - // want: false, - // }, } for _, tt := range tests { t.Run(tt.fileName, func(t *testing.T) { - if got := matchEditedName(tt.jsonName, tt.fileName, immich.DefaultSupportedMedia); got != tt.want { - t.Errorf("matchEditedName() = %v, want %v", got, tt.want) + matcher := "" + for _, m := range matchers { + if m.fn(tt.jsonName, tt.fileName, immich.DefaultSupportedMedia) { + matcher = m.name + break + } + } + if matcher != tt.want { + t.Errorf("matcher is '%s', want %v", matcher, tt.want) } }) } @@ -125,3 +182,37 @@ func Test_matchForgottenDuplicates(t *testing.T) { }) } } + +/* indexes, but false +goos: linux +goarch: amd64 +pkg: github.com/simulot/immich-go/browser/gp +cpu: Intel(R) Core(TM) i7-10750H CPU @ 2.60GHz +Benchmark_matchDuplicateInYear-12 27067428 52.06 ns/op 0 B/op 0 allocs/op +PASS +ok github.com/simulot/immich-go/browser/gp 1.458s + +goos: linux +goarch: amd64 +pkg: github.com/simulot/immich-go/browser/gp +cpu: Intel(R) Core(TM) i7-10750H CPU @ 2.60GHz +Benchmark_matchDuplicateInYear-12 881652 1491 ns/op 240 B/op 4 allocs/op +PASS +ok github.com/simulot/immich-go/browser/gp 1.332s + + +goos: linux +goarch: amd64 +pkg: github.com/simulot/immich-go/browser/gp +cpu: Intel(R) Core(TM) i7-10750H CPU @ 2.60GHz +Benchmark_matchDuplicateInYear-12 25737067 43.88 ns/op 0 B/op 0 allocs/op +PASS +ok github.com/simulot/immich-go/browser/gp 1.180s + +*/ + +func Benchmark_matchDuplicateInYear(b *testing.B) { + for i := 0; i < b.N; i++ { + matchDuplicateInYear("IMG_3479.JPG(2).json", "IMG_3479(2).JPG", nil) + } +} diff --git a/browser/gp/testgp_bigread_test.go b/browser/gp/testgp_bigread_test.go index a0d3304e..d3283a6e 100644 --- a/browser/gp/testgp_bigread_test.go +++ b/browser/gp/testgp_bigread_test.go @@ -31,7 +31,7 @@ func TestReadBigTakeout(t *testing.T) { return } cnt := 0 - fsyss, err := fshelper.ParsePath(m, true) + fsyss, err := fshelper.ParsePath(m) to, err := NewTakeout(context.Background(), j, immich.DefaultSupportedMedia, fsyss...) if err != nil { t.Error(err) diff --git a/browser/gp/testgp_samples_test.go b/browser/gp/testgp_samples_test.go index 5853d950..85b4d88c 100644 --- a/browser/gp/testgp_samples_test.go +++ b/browser/gp/testgp_samples_test.go @@ -4,6 +4,7 @@ import ( "bytes" "encoding/json" "errors" + "io/fs" "path" "sort" "strconv" @@ -12,6 +13,7 @@ import ( "github.com/psanford/memfs" "github.com/simulot/immich-go/immich/metadata" + "github.com/simulot/immich-go/internal/fakefs" ) type inMemFS struct { @@ -25,6 +27,10 @@ func newInMemFS() *inMemFS { } } +func (mfs *inMemFS) FSs() []fs.FS { + return []fs.FS{mfs} +} + func (mfs *inMemFS) addFile(name string, content []byte) *inMemFS { if mfs.err != nil { return mfs @@ -113,110 +119,239 @@ func sortFileResult(s []fileResult) []fileResult { return s } -func simpleYear() *inMemFS { +func simpleYear() []fs.FS { + return newInMemFS(). + addJSONImage("Photos from 2023/PXL_20230922_144936660.jpg.json", "PXL_20230922_144936660.jpg"). + addImage("Photos from 2023/PXL_20230922_144936660.jpg", 10). + addJSONImage("Photos from 2023/PXL_20230922_144956000.jpg.json", "PXL_20230922_144956000.jpg"). + addImage("Photos from 2023/PXL_20230922_144956000.jpg", 20).FSs() +} + +func simpleAlbum() []fs.FS { + return newInMemFS(). + addJSONImage("Photos from 2020/IMG_8172.jpg.json", "IMG_8172.jpg", takenTime("20200101103000")). + addImage("Photos from 2020/IMG_8172.jpg", 25). + addJSONImage("Photos from 2023/PXL_20230922_144936660.jpg.json", "PXL_20230922_144936660.jpg", takenTime("PXL_20230922_144936660")). + addJSONImage("Photos from 2023/PXL_20230922_144934440.jpg.json", "PXL_20230922_144934440.jpg", takenTime("PXL_20230922_144934440")). + addJSONImage("Photos from 2023/IMG_8172.jpg.json", "IMG_8172.jpg", takenTime("20230922102100")). + addImage("Photos from 2023/PXL_20230922_144936660.jpg", 10). + addImage("Photos from 2023/PXL_20230922_144934440.jpg", 15). + addImage("Photos from 2023/IMG_8172.jpg", 52). + addJSONAlbum("Album/anyname.json", "Album"). + addJSONImage("Album/IMG_8172.jpg.json", "IMG_8172.jpg", takenTime("20230922102100")). + addJSONImage("Album/PXL_20230922_144936660.jpg.json", "PXL_20230922_144936660.jpg", takenTime("PXL_20230922_144936660")). + addImage("Album/IMG_8172.jpg", 52). + addImage("Album/PXL_20230922_144936660.jpg", 10).FSs() +} + +func albumWithoutImage() []fs.FS { return newInMemFS(). - addJSONImage("Takeout/Google Photos/Photos from 2023/PXL_20230922_144936660.jpg.json", "PXL_20230922_144936660.jpg"). - addImage("Takeout/Google Photos/Photos from 2023/PXL_20230922_144936660.jpg", 10). - addJSONImage("Takeout/Google Photos/Photos from 2023/PXL_20230922_144956000.jpg.json", "PXL_20230922_144956000.jpg"). - addImage("Takeout/Google Photos/Photos from 2023/PXL_20230922_144956000.jpg", 20) + addJSONAlbum("Album/anyname.json", "Album"). + addJSONImage("Album/PXL_20230922_144936660.jpg.json", "PXL_20230922_144936660.jpg"). + addJSONImage("Album/PXL_20230922_144934440.jpg.json", "PXL_20230922_144934440.jpg"). + addImage("Album/PXL_20230922_144936660.jpg", 10). + addJSONImage("Photos from 2023/PXL_20230922_144934440.jpg.json", "PXL_20230922_144934440.jpg"). + addJSONImage("Photos from 2023/PXL_20230922_144936660.jpg.json", "PXL_20230922_144936660.jpg"). + addImage("Photos from 2023/PXL_20230922_144934440.jpg", 15). + addImage("Photos from 2023/PXL_20230922_144936660.jpg", 10).FSs() } -func simpleAlbum() *inMemFS { +func namesWithNumbers() []fs.FS { return newInMemFS(). - addJSONImage("Takeout/Google Photos/Photos from 2023/PXL_20230922_144936660.jpg.json", "PXL_20230922_144936660.jpg", takenTime("PXL_20230922_144936660")). - addImage("Takeout/Google Photos/Photos from 2023/PXL_20230922_144936660.jpg", 10). - addJSONImage("Takeout/Google Photos/Photos from 2023/PXL_20230922_144934440.jpg.json", "PXL_20230922_144934440.jpg", takenTime("PXL_20230922_144934440")). - addImage("Takeout/Google Photos/Photos from 2023/PXL_20230922_144934440.jpg", 15). - addJSONAlbum("Takeout/Google Photos/Album/anyname.json", "Album"). - addJSONImage("Takeout/Google Photos/Album/PXL_20230922_144936660.jpg.json", "PXL_20230922_144936660.jpg", takenTime("PXL_20230922_144936660")). - addImage("Takeout/Google Photos/Album/PXL_20230922_144936660.jpg", 10). - addJSONImage("Takeout/Google Photos/Photos from 2023/IMG_8172.jpg.json", "IMG_8172.jpg", takenTime("20230922102100")). - addImage("Takeout/Google Photos/Photos from 2023/IMG_8172.jpg", 52). - addJSONImage("Takeout/Google Photos/Album/IMG_8172.jpg.json", "IMG_8172.jpg", takenTime("20230922102100")). - addImage("Takeout/Google Photos/Album/IMG_8172.jpg", 52). - addJSONImage("Takeout/Google Photos/Photos from 2020/IMG_8172.jpg.json", "IMG_8172.jpg", takenTime("20200101103000")). - addImage("Takeout/Google Photos/Photos from 2020/IMG_8172.jpg", 25) -} - -func albumWithoutImage() *inMemFS { + addJSONImage("Photos from 2009/IMG_3479.JPG.json", "IMG_3479.JPG"). + addImage("Photos from 2009/IMG_3479.JPG", 10). + addJSONImage("Photos from 2009/IMG_3479.JPG(1).json", "IMG_3479.JPG"). + addImage("Photos from 2009/IMG_3479(1).JPG", 12). + addJSONImage("Photos from 2009/IMG_3479.JPG(2).json", "IMG_3479.JPG"). + addImage("Photos from 2009/IMG_3479(2).JPG", 15).FSs() +} + +func namesTruncated() []fs.FS { return newInMemFS(). - addJSONImage("Takeout/Google Photos/Photos from 2023/PXL_20230922_144936660.jpg.json", "PXL_20230922_144936660.jpg"). - addImage("Takeout/Google Photos/Photos from 2023/PXL_20230922_144936660.jpg", 10). - addJSONImage("Takeout/Google Photos/Photos from 2023/PXL_20230922_144934440.jpg.json", "PXL_20230922_144934440.jpg"). - addImage("Takeout/Google Photos/Photos from 2023/PXL_20230922_144934440.jpg", 15). - addJSONAlbum("Takeout/Google Photos/Album/anyname.json", "Album"). - addJSONImage("Takeout/Google Photos/Album/PXL_20230922_144936660.jpg.json", "PXL_20230922_144936660.jpg"). - addImage("Takeout/Google Photos/Album/PXL_20230922_144936660.jpg", 10). - addJSONImage("Takeout/Google Photos/Album/PXL_20230922_144934440.jpg.json", "PXL_20230922_144934440.jpg") + addJSONImage("Photos from 2023/😀😃😄😁😆😅😂🤣🥲☺️😊😇🙂🙃😉😌😍🥰😘😗😙😚😋.json", "😀😃😄😁😆😅😂🤣🥲☺️😊😇🙂🙃😉😌😍🥰😘😗😙😚😋😛😝😜🤪🤨🧐🤓😎🥸🤩🥳😏😒😞😔😟😕🙁☹️😣😖😫😩🥺😢😭😤😠😡🤬🤯😳🥵🥶.jpg"). + addImage("Photos from 2023/😀😃😄😁😆😅😂🤣🥲☺️😊😇🙂🙃😉😌😍🥰😘😗😙😚😋😛.jpg", 10). + addJSONImage("Photos from 2023/PXL_20230809_203449253.LONG_EXPOSURE-02.ORIGIN.json", "PXL_20230809_203449253.LONG_EXPOSURE-02.ORIGINAL.jpg"). + addImage("Photos from 2023/PXL_20230809_203449253.LONG_EXPOSURE-02.ORIGINA.jpg", 40). + addJSONImage("Photos from 2023/05yqt21kruxwwlhhgrwrdyb6chhwszi9bqmzu16w0 2.jp.json", "05yqt21kruxwwlhhgrwrdyb6chhwszi9bqmzu16w0 2.jpg"). + addImage("Photos from 2023/05yqt21kruxwwlhhgrwrdyb6chhwszi9bqmzu16w0 2.jpg", 25).FSs() } -func namesWithNumbers() *inMemFS { +func imagesEditedJSON() []fs.FS { return newInMemFS(). - addJSONImage("Takeout/Google Photos/Photos from 2009/IMG_3479.JPG.json", "IMG_3479.JPG"). - addImage("Takeout/Google Photos/Photos from 2009/IMG_3479.JPG", 10). - addJSONImage("Takeout/Google Photos/Photos from 2009/IMG_3479.JPG(1).json", "IMG_3479.JPG"). - addImage("Takeout/Google Photos/Photos from 2009/IMG_3479(1).JPG", 12). - addJSONImage("Takeout/Google Photos/Photos from 2009/IMG_3479.JPG(2).json", "IMG_3479.JPG"). - addImage("Takeout/Google Photos/Photos from 2009/IMG_3479(2).JPG", 15) + addJSONImage("Photos from 2023/PXL_20220405_090123740.PORTRAIT.jpg.json", "PXL_20220405_090123740.PORTRAIT.jpg"). + addImage("Photos from 2023/PXL_20220405_090123740.PORTRAIT.jpg", 41). + addImage("Photos from 2023/PXL_20220405_090123740.PORTRAIT-modifié.jpg", 21). + addImage("Photos from 2023/PXL_20220405_090200110.PORTRAIT-modifié.jpg", 12).FSs() } -func namesTruncated() *inMemFS { +func titlesWithForbiddenChars() []fs.FS { return newInMemFS(). - addJSONImage("Takeout/Google Photos/Photos from 2023/😀😃😄😁😆😅😂🤣🥲☺️😊😇🙂🙃😉😌😍🥰😘😗😙😚😋.json", "😀😃😄😁😆😅😂🤣🥲☺️😊😇🙂🙃😉😌😍🥰😘😗😙😚😋😛😝😜🤪🤨🧐🤓😎🥸🤩🥳😏😒😞😔😟😕🙁☹️😣😖😫😩🥺😢😭😤😠😡🤬🤯😳🥵🥶.jpg"). - addImage("Takeout/Google Photos/Photos from 2023/😀😃😄😁😆😅😂🤣🥲☺️😊😇🙂🙃😉😌😍🥰😘😗😙😚😋😛.jpg", 10). - addJSONImage("Takeout/Google Photos/Photos from 2023/PXL_20230809_203449253.LONG_EXPOSURE-02.ORIGIN.json", "PXL_20230809_203449253.LONG_EXPOSURE-02.ORIGINAL.jpg"). - addImage("Takeout/Google Photos/Photos from 2023/PXL_20230809_203449253.LONG_EXPOSURE-02.ORIGINA.jpg", 40). - addJSONImage("Takeout/Google Photos/Photos from 2023/05yqt21kruxwwlhhgrwrdyb6chhwszi9bqmzu16w0 2.jp.json", "05yqt21kruxwwlhhgrwrdyb6chhwszi9bqmzu16w0 2.jpg"). - addImage("Takeout/Google Photos/Photos from 2023/05yqt21kruxwwlhhgrwrdyb6chhwszi9bqmzu16w0 2.jpg", 25) + addJSONImage("Photos from 2012/27_06_12 - 1.mov.json", "27/06/12 - 1", takenTime("20120627")). + addImage("Photos from 2012/27_06_12 - 1.mov", 52). + addJSONImage("Photos from 2012/27_06_12 - 2.json", "27/06/12 - 2", takenTime("20120627")). + addImage("Photos from 2012/27_06_12 - 2.jpg", 24).FSs() } -func imagesEditedJSON() *inMemFS { +func namesIssue39() []fs.FS { return newInMemFS(). - addJSONImage("Takeout/Google Photos/Photos from 2023/PXL_20220405_090123740.PORTRAIT.jpg.json", "PXL_20220405_090123740.PORTRAIT.jpg"). - addImage("Takeout/Google Photos/Photos from 2023/PXL_20220405_090123740.PORTRAIT.jpg", 41). - addImage("Takeout/Google Photos/Photos from 2023/PXL_20220405_090123740.PORTRAIT-modifié.jpg", 21). - addImage("Takeout/Google Photos/Photos from 2023/PXL_20220405_090200110.PORTRAIT-modifié.jpg", 12) + addJSONAlbum("Album/anyname.json", "Album"). + addJSONImage("Album/Backyard_ceremony_wedding_photography_xxxxxxx_.json", "Backyard_ceremony_wedding_photography_xxxxxxx_magnoliastudios-371.jpg", takenTime("20200101")). + addJSONImage("Album/Backyard_ceremony_wedding_photography_xxxxxxx_(1).json", "Backyard_ceremony_wedding_photography_xxxxxxx_magnoliastudios-181.jpg", takenTime("20200101")). + addJSONImage("Album/Backyard_ceremony_wedding_photography_xxxxxxx_(494).json", "Backyard_ceremony_wedding_photography_markham_magnoliastudios-19.jpg", takenTime("20200101")). + addImage("Album/Backyard_ceremony_wedding_photography_xxxxxxx_m.jpg", 1). + addImage("Album/Backyard_ceremony_wedding_photography_xxxxxxx_m(1).jpg", 181). + addImage("Album/Backyard_ceremony_wedding_photography_xxxxxxx_m(494).jpg", 494). + addJSONImage("Photos from 2020/Backyard_ceremony_wedding_photography_xxxxxxx_.json", "Backyard_ceremony_wedding_photography_xxxxxxx_magnoliastudios-371.jpg", takenTime("20200101")). + addJSONImage("Photos from 2020/Backyard_ceremony_wedding_photography_xxxxxxx_(1).json", "Backyard_ceremony_wedding_photography_xxxxxxx_magnoliastudios-181.jpg", takenTime("20200101")). + addJSONImage("Photos from 2020/Backyard_ceremony_wedding_photography_xxxxxxx_(494).json", "Backyard_ceremony_wedding_photography_markham_magnoliastudios-19.jpg", takenTime("20200101")). + addImage("Photos from 2020/Backyard_ceremony_wedding_photography_xxxxxxx_m(1).jpg", 181). + addImage("Photos from 2020/Backyard_ceremony_wedding_photography_xxxxxxx_m(494).jpg", 494). + addImage("Photos from 2020/Backyard_ceremony_wedding_photography_xxxxxxx_m.jpg", 1).FSs() } -func titlesWithForbiddenChars() *inMemFS { +func issue68MPFiles() []fs.FS { return newInMemFS(). - addJSONImage("Takeout/Google Photos/Photos from 2012/27_06_12 - 1.mov.json", "27/06/12 - 1", takenTime("20120627")). - addImage("Takeout/Google Photos/Photos from 2012/27_06_12 - 1.mov", 52). - addJSONImage("Takeout/Google Photos/Photos from 2012/27_06_12 - 2.json", "27/06/12 - 2", takenTime("20120627")). - addImage("Takeout/Google Photos/Photos from 2012/27_06_12 - 2.jpg", 24) + addJSONImage("Photos from 2022/PXL_20221228_185930354.MP.jpg.json", "PXL_20221228_185930354.MP.jpg", takenTime("20220101")). + addImage("Photos from 2022/PXL_20221228_185930354.MP", 1). + addImage("Photos from 2022/PXL_20221228_185930354.MP.jpg", 2).FSs() } -func namesIssue39() *inMemFS { +func issue68LongExposure() []fs.FS { return newInMemFS(). - addJSONAlbum("Takeout/Google Photos/Album/anyname.json", "Album"). - addJSONImage("Takeout/Google Photos/Album/Backyard_ceremony_wedding_photography_xxxxxxx_.json", "Backyard_ceremony_wedding_photography_xxxxxxx_magnoliastudios-371.jpg", takenTime("20200101")). - addImage("Takeout/Google Photos/Album/Backyard_ceremony_wedding_photography_xxxxxxx_m.jpg", 1). - addImage("Takeout/Google Photos/Photos from 2020/Backyard_ceremony_wedding_photography_xxxxxxx_m.jpg", 1). - addJSONImage("Takeout/Google Photos/Album/Backyard_ceremony_wedding_photography_xxxxxxx_(1).json", "Backyard_ceremony_wedding_photography_xxxxxxx_magnoliastudios-181.jpg", takenTime("20200101")). - addImage("Takeout/Google Photos/Album/Backyard_ceremony_wedding_photography_xxxxxxx_m(1).jpg", 181). - addImage("Takeout/Google Photos/Photos from 2020/Backyard_ceremony_wedding_photography_xxxxxxx_m(1).jpg", 181). - addJSONImage("Takeout/Google Photos/Album/Backyard_ceremony_wedding_photography_xxxxxxx_(494).json", "Backyard_ceremony_wedding_photography_markham_magnoliastudios-19.jpg", takenTime("20200101")). - addImage("Takeout/Google Photos/Photos from 2020/Backyard_ceremony_wedding_photography_xxxxxxx_m(494).jpg", 494) -} - -func issue68MPFiles() *inMemFS { + addJSONImage("Photos from 2023/PXL_20230814_201154491.LONG_EXPOSURE-01.COVER..json", "PXL_20230814_201154491.LONG_EXPOSURE-01.COVER.jpg", takenTime("20230101")). + addImage("Photos from 2023/PXL_20230814_201154491.LONG_EXPOSURE-01.COVER.jpg", 1). + addJSONImage("Photos from 2023/PXL_20230814_201154491.LONG_EXPOSURE-02.ORIGIN.json", "PXL_20230814_201154491.LONG_EXPOSURE-02.ORIGINAL.jpg", takenTime("20230101")). + addImage("Photos from 2023/PXL_20230814_201154491.LONG_EXPOSURE-02.ORIGINA.jpg", 2).FSs() +} + +func issue68ForgottenDuplicates() []fs.FS { return newInMemFS(). - addJSONImage("Takeout/Google Photos/Photos from 2022/PXL_20221228_185930354.MP.jpg.json", "PXL_20221228_185930354.MP.jpg", takenTime("20220101")). - addImage("Takeout/Google Photos/Photos from 2022/PXL_20221228_185930354.MP", 1). - addImage("Takeout/Google Photos/Photos from 2022/PXL_20221228_185930354.MP.jpg", 2) + addJSONImage("Photos from 2022/original_1d4caa6f-16c6-4c3d-901b-9387de10e528_.json", "original_1d4caa6f-16c6-4c3d-901b-9387de10e528_PXL_20220516_164814158.jpg", takenTime("20220101")). + addImage("Photos from 2022/original_1d4caa6f-16c6-4c3d-901b-9387de10e528_P.jpg", 1). + addImage("Photos from 2022/original_1d4caa6f-16c6-4c3d-901b-9387de10e528_P(1).jpg", 2).FSs() } -func issue68LongExposure() *inMemFS { +// #390 Question: report shows way less images uploaded than scanned +func issue390WrongCount() []fs.FS { return newInMemFS(). - addJSONImage("Takeout/Google Photos/Photos from 2023/PXL_20230814_201154491.LONG_EXPOSURE-01.COVER..json", "PXL_20230814_201154491.LONG_EXPOSURE-01.COVER.jpg", takenTime("20230101")). - addImage("Takeout/Google Photos/Photos from 2023/PXL_20230814_201154491.LONG_EXPOSURE-01.COVER.jpg", 1). - addJSONImage("Takeout/Google Photos/Photos from 2023/PXL_20230814_201154491.LONG_EXPOSURE-02.ORIGIN.json", "PXL_20230814_201154491.LONG_EXPOSURE-02.ORIGINAL.jpg", takenTime("20230101")). - addImage("Takeout/Google Photos/Photos from 2023/PXL_20230814_201154491.LONG_EXPOSURE-02.ORIGINA.jpg", 2) + addJSONImage("Takeout/Google Photos/Photos from 2021/image000000.jpg.json", "image000000.jpg"). + addJSONImage("Takeout/Google Photos/Photos from 2021/image000000.jpg(1).json", "image000000.jpg"). + addJSONImage("Takeout/Google Photos/Photos from 2021/image000000.gif.json", "image000000.gif.json"). + addImage("Takeout/Google Photos/Photos from 2021/image000000.gif", 10). + addImage("Takeout/Google Photos/Photos from 2021/image000000.jpg", 20).FSs() } -func issue68ForgottenDuplicates() *inMemFS { +func issue390WrongCount2() []fs.FS { return newInMemFS(). - addJSONImage("Takeout/Google Photos/Photos from 2022/original_1d4caa6f-16c6-4c3d-901b-9387de10e528_.json", "original_1d4caa6f-16c6-4c3d-901b-9387de10e528_PXL_20220516_164814158.jpg", takenTime("20220101")). - addImage("Takeout/Google Photos/Photos from 2022/original_1d4caa6f-16c6-4c3d-901b-9387de10e528_P.jpg", 1). - addImage("Takeout/Google Photos/Photos from 2022/original_1d4caa6f-16c6-4c3d-901b-9387de10e528_P(1).jpg", 2) + addJSONImage("Takeout/Google Photos/2017 - Croatia/IMG_0170.jpg.json", "IMG_0170.jpg"). + addJSONImage("Takeout/Google Photos/Photos from 2018/IMG_0170.JPG.json", "IMG_0170.JPG"). + addJSONImage("Takeout/Google Photos/Photos from 2018/IMG_0170.HEIC.json", "IMG_0170.HEIC"). + addJSONImage("Takeout/Google Photos/Photos from 2023/IMG_0170.HEIC.json", "IMG_0170.HEIC"). + addJSONImage("Takeout/Google Photos/2018 - Cambodia/IMG_0170.JPG.json", "IMG_0170.JPG"). + addJSONImage("Takeout/Google Photos/2023 - Belize/IMG_0170.HEIC.json", "IMG_0170.HEIC"). + addJSONImage("Takeout/Google Photos/Photos from 2017/IMG_0170.jpg.json", "IMG_0170.jpg"). + addImage("Takeout/Google Photos/2017 - Croatia/IMG_0170.jpg", 514963). + addImage("Takeout/Google Photos/Photos from 2018/IMG_0170.HEIC", 1332980). + addImage("Takeout/Google Photos/Photos from 2018/IMG_0170.JPG", 4570661). + addImage("Takeout/Google Photos/Photos from 2023/IMG_0170.MP4", 6024972). + addImage("Takeout/Google Photos/Photos from 2023/IMG_0170.HEIC", 4443973). + addImage("Takeout/Google Photos/Photos from 2018/IMG_0170.MP4", 2288647). + addImage("Takeout/Google Photos/2018 - Cambodia/IMG_0170.JPG", 4570661). + addImage("Takeout/Google Photos/2023 - Belize/IMG_0170.MP4", 6024972). + addImage("Takeout/Google Photos/2023 - Belize/IMG_0170.HEIC", 4443973). + addImage("Takeout/Google Photos/Photos from 2017/IMG_0170.jpg", 514963).FSs() +} + +func checkLivePhoto() []fs.FS { + return newInMemFS(). + addJSONImage("Motion test/20231227_152817.jpg.json", "20231227_152817.jpg"). + addImage("Motion test/20231227_152817.jpg", 7426453). + addImage("Motion test/20231227_152817.MP4", 5192477). + addJSONImage("Motion Test/PXL_20231118_035751175.MP.jpg.json", "20231118_035751175.MP.jpg"). + addImage("Motion Test/PXL_20231118_035751175.MP", 3478685). + addImage("Motion Test/PXL_20231118_035751175.MP.jpg", 8025699).FSs() +} + +func loadFromString(dateFormat string, s string) []fs.FS { + fss, err := fakefs.ScanStringList(dateFormat, s) + if err != nil { + panic(err.Error()) + } + return fss +} + +func checkLivePhotoPixil() []fs.FS { + return loadFromString("01-02-2006 15:04", `Archive: takeout-20230720T065335Z-001.zip + Length Date Time Name +--------- ---------- ----- ---- + 309 03-05-2023 10:10 Takeout/Google Photos/2022 - Germany/metadata.json + 801 07-19-2023 23:59 Takeout/Google Photos/2022 - Germany/IMG_4573.HEIC.json + 2232086 07-19-2023 23:59 Takeout/Google Photos/2022 - Germany/IMG_4573.MP4 + 3530351 07-20-2023 00:00 Takeout/Google Photos/2022 - Germany/IMG_4573.HEIC + 319 03-05-2023 10:10 Takeout/Google Photos/2022 - Germany - Private/metadata.json + 802 07-20-2023 00:03 Takeout/Google Photos/2022 - Germany - Private/IMG_4573.HEIC.json + 3530351 07-19-2023 23:56 Takeout/Google Photos/2022 - Germany - Private/IMG_4573.HEIC + 2232086 07-19-2023 23:56 Takeout/Google Photos/2022 - Germany - Private/IMG_4573.MP4 + 803 07-19-2023 23:58 Takeout/Google Photos/Photos from 2022/IMG_4573.HEIC.json + 3530351 07-19-2023 23:59 Takeout/Google Photos/Photos from 2022/IMG_4573.HEIC + 2232086 07-19-2023 23:59 Takeout/Google Photos/Photos from 2022/IMG_4573.MP4 +`) +} + +func checkMissingJSON() []fs.FS { + return loadFromString("01-02-2006 15:04", `Archive: takeout-20230720T065335Z-001.zip + Length Date Time Name +--------- ---------- ----- ---- + 803 07-19-2023 23:58 Takeout/Google Photos/Photos from 2022/IMG_4573.HEIC.json + 3530351 07-19-2023 23:59 Takeout/Google Photos/Photos from 2022/IMG_4573.HEIC + 1352455 2024-07-12 15:18 Takeout/Google Foto/Photos from 2016/IMG-20161201-WA0035.jpeg + 3530351 07-19-2023 23:56 Takeout/Google Photos/2022 - Germany - Private/IMG_4553.HEIC + 309 03-05-2023 10:10 Takeout/Google Photos/2022 - Germany/metadata.json + 2232086 07-19-2023 23:59 Takeout/Google Photos/2022 - Germany/IMG_1234.MP4 + 3530351 07-20-2023 00:00 Takeout/Google Photos/2022 - Germany/IMG_1234.HEIC +`) +} + +func checkDuplicates() []fs.FS { + return loadFromString("01-02-2006 15:04", `Archive: takeout-20230720T065335Z-001.zip +-rw-r--r-- 0/0 365022 2024-07-19 01:19 Takeout/Google Foto/[E&S] 2016-01-05 - Castello De Albertis e Mostra d/20160105_121621_LLS.jpg +-rw-r--r-- 0/0 708 2024-07-19 01:19 Takeout/Google Foto/[E&S] 2016-01-05 - Castello De Albertis e Mostra d/20160105_121621_LLS.jpg.json +-rw-r--r-- 0/0 364041 2024-07-19 01:51 Takeout/Google Foto/Photos from 2016/20160105_121621_LLS.jpg +-rw-r--r-- 0/0 709 2024-07-19 01:51 Takeout/Google Foto/Photos from 2016/20160105_121621_LLS.jpg.json +-rw-r--r-- 0/0 708 2024-07-19 02:13 Takeout/Google Foto/2016-01-05 - _3/20160105_121621_LLS.jpg.json +-rw-r--r-- 0/0 364041 2024-07-19 02:20 Takeout/Google Foto/2016-01-05 - _3/20160105_121621_LLS.jpg +Archive: takeout-20230720T065335Z-002.zip +-rw-r--r-- 0/0 364041 2024-07-19 06:14 Takeout/Google Foto/2016-01-05 - _3/20160105_121621_LLS.jpg +-rw-r--r-- 0/0 708 2024-07-19 02:13 Takeout/Google Foto/2016-01-05 - _3/20160105_121621_LLS.jpg.json +`) +} + +/* +func checkMP_405() []fs.FS { + return loadFromString("2006-01-02 15:04", `Archive: takeout-20230720T065335Z-001.zip + 893 2024-01-21 16:33 Takeout/Google Photos/Family _ friends/PXL_20210102_221126856.MP.jpg.json + 896 2024-01-21 16:33 Takeout/Google Photos/Family _ friends/PXL_20210102_221126856.MP~2.jpg.json + 895 2024-01-21 16:52 Takeout/Google Photos/Untitled(1)/PXL_20210102_221126856.MP~2.jpg.json + 893 2024-01-21 16:52 Takeout/Google Photos/Untitled(1)/PXL_20210102_221126856.MP.jpg.json + 893 2024-01-21 17:46 Takeout/Google Photos/Photos from 2021/PXL_20210102_221126856.MP.jpg.json + 895 2024-01-21 17:46 Takeout/Google Photos/Photos from 2021/PXL_20210102_221126856.MP~2.jpg.json + 3242290 2024-01-21 16:58 Takeout/Google Photos/Untitled(1)/PXL_20210102_221126856.MP + 1214365 2024-01-21 16:58 Takeout/Google Photos/Untitled(1)/PXL_20210102_221126856.MP~2 + 4028710 2024-01-21 16:59 Takeout/Google Photos/Untitled(1)/PXL_20210102_221126856.MP~2.jpg + 6486725 2024-01-21 16:59 Takeout/Google Photos/Untitled(1)/PXL_20210102_221126856.MP.jpg + 1214365 2024-01-21 15:40 Takeout/Google Photos/Family _ friends/PXL_20210102_221126856.MP~2 + 3242290 2024-01-21 15:40 Takeout/Google Photos/Family _ friends/PXL_20210102_221126856.MP + 6486725 2024-01-21 15:41 Takeout/Google Photos/Family _ friends/PXL_20210102_221126856.MP.jpg + 4028710 2024-01-21 15:41 Takeout/Google Photos/Family _ friends/PXL_20210102_221126856.MP~2.jpg + 3242290 2024-01-21 17:53 Takeout/Google Photos/Photos from 2021/PXL_20210102_221126856.MP + 1214365 2024-01-21 17:53 Takeout/Google Photos/Photos from 2021/PXL_20210102_221126856.MP~2 + 6486725 2024-01-21 17:53 Takeout/Google Photos/Photos from 2021/PXL_20210102_221126856.MP.jpg + 4028710 2024-01-21 17:53 Takeout/Google Photos/Photos from 2021/PXL_20210102_221126856.MP~2.jpg + 1214365 2024-01-21 16:14 Takeout/Google Photos/pi_info/PXL_20210102_221126856.MP~2 + 3242290 2024-01-21 16:14 Takeout/Google Photos/pi_info/PXL_20210102_221126856.MP + 892 2024-01-21 16:14 Takeout/Google Photos/pi_info/PXL_20210102_221126856.MP.jpg.json + 895 2024-01-21 16:14 Takeout/Google Photos/pi_info/PXL_20210102_221126856.MP~2.jpg.json + 4028710 2024-01-21 16:14 Takeout/Google Photos/pi_info/PXL_20210102_221126856.MP~2.jpg + 6486725 2024-01-21 16:14 Takeout/Google Photos/pi_info/PXL_20210102_221126856.MP.jpg`) } +*/ diff --git a/browser/gp/testgp_test.go b/browser/gp/testgp_test.go index 9d194e43..677cfa68 100644 --- a/browser/gp/testgp_test.go +++ b/browser/gp/testgp_test.go @@ -3,6 +3,7 @@ package gp import ( "context" "io" + "io/fs" "log/slog" "path" "reflect" @@ -15,9 +16,9 @@ import ( func TestBrowse(t *testing.T) { tc := []struct { - name string - gen func() *inMemFS - results []fileResult // file name / title + name string + gen func() []fs.FS + want []fileResult // file name / title }{ { "simpleYear", simpleYear, @@ -30,16 +31,19 @@ func TestBrowse(t *testing.T) { { "simpleAlbum", simpleAlbum, sortFileResult([]fileResult{ + {name: "PXL_20230922_144936660.jpg", size: 10, title: "PXL_20230922_144936660.jpg"}, {name: "PXL_20230922_144936660.jpg", size: 10, title: "PXL_20230922_144936660.jpg"}, {name: "PXL_20230922_144934440.jpg", size: 15, title: "PXL_20230922_144934440.jpg"}, - {name: "IMG_8172.jpg", size: 52, title: "IMG_8172.jpg"}, {name: "IMG_8172.jpg", size: 25, title: "IMG_8172.jpg"}, + {name: "IMG_8172.jpg", size: 52, title: "IMG_8172.jpg"}, + {name: "IMG_8172.jpg", size: 52, title: "IMG_8172.jpg"}, }), }, { "albumWithoutImage", albumWithoutImage, sortFileResult([]fileResult{ + {name: "PXL_20230922_144936660.jpg", size: 10, title: "PXL_20230922_144936660.jpg"}, {name: "PXL_20230922_144936660.jpg", size: 10, title: "PXL_20230922_144936660.jpg"}, {name: "PXL_20230922_144934440.jpg", size: 15, title: "PXL_20230922_144934440.jpg"}, }), @@ -79,14 +83,18 @@ func TestBrowse(t *testing.T) { { "namesIssue39", namesIssue39, sortFileResult([]fileResult{ + {name: "Backyard_ceremony_wedding_photography_xxxxxxx_m.jpg", size: 1, title: "Backyard_ceremony_wedding_photography_xxxxxxx_magnoliastudios-371.jpg"}, {name: "Backyard_ceremony_wedding_photography_xxxxxxx_m.jpg", size: 1, title: "Backyard_ceremony_wedding_photography_xxxxxxx_magnoliastudios-371.jpg"}, {name: "Backyard_ceremony_wedding_photography_xxxxxxx_m(1).jpg", size: 181, title: "Backyard_ceremony_wedding_photography_xxxxxxx_magnoliastudios-181.jpg"}, + {name: "Backyard_ceremony_wedding_photography_xxxxxxx_m(1).jpg", size: 181, title: "Backyard_ceremony_wedding_photography_xxxxxxx_magnoliastudios-181.jpg"}, + {name: "Backyard_ceremony_wedding_photography_xxxxxxx_m(494).jpg", size: 494, title: "Backyard_ceremony_wedding_photography_markham_magnoliastudios-19.jpg"}, {name: "Backyard_ceremony_wedding_photography_xxxxxxx_m(494).jpg", size: 494, title: "Backyard_ceremony_wedding_photography_markham_magnoliastudios-19.jpg"}, }), }, { "issue68MPFiles", issue68MPFiles, sortFileResult([]fileResult{ + {name: "PXL_20221228_185930354.MP", size: 1, title: "PXL_20221228_185930354.MP"}, {name: "PXL_20221228_185930354.MP.jpg", size: 2, title: "PXL_20221228_185930354.MP.jpg"}, }), }, @@ -105,19 +113,38 @@ func TestBrowse(t *testing.T) { {name: "original_1d4caa6f-16c6-4c3d-901b-9387de10e528_P(1).jpg", size: 2, title: "original_1d4caa6f-16c6-4c3d-901b-9387de10e528_PXL_20220516_164814158.jpg"}, }), }, + { + "issue390WrongCount", issue390WrongCount, + sortFileResult([]fileResult{ + {name: "image000000.gif", size: 10, title: "image000000.gif"}, + {name: "image000000.jpg", size: 20, title: "image000000.jpg"}, + }), + }, + { + "issue390WrongCount2", issue390WrongCount2, + sortFileResult([]fileResult{ + {name: "IMG_0170.jpg", size: 514963, title: "IMG_0170.jpg"}, + {name: "IMG_0170.HEIC", size: 1332980, title: "IMG_0170.HEIC"}, + {name: "IMG_0170.JPG", size: 4570661, title: "IMG_0170.JPG"}, + {name: "IMG_0170.MP4", size: 6024972, title: "IMG_0170.MP4"}, + {name: "IMG_0170.HEIC", size: 4443973, title: "IMG_0170.HEIC"}, + {name: "IMG_0170.MP4", size: 2288647, title: "IMG_0170.MP4"}, + {name: "IMG_0170.JPG", size: 4570661, title: "IMG_0170.JPG"}, + {name: "IMG_0170.MP4", size: 6024972, title: "IMG_0170.MP4"}, + {name: "IMG_0170.HEIC", size: 4443973, title: "IMG_0170.HEIC"}, + {name: "IMG_0170.jpg", size: 514963, title: "IMG_0170.jpg"}, + }), + }, } for _, c := range tc { t.Run(c.name, func(t *testing.T) { fsys := c.gen() - if fsys.err != nil { - t.Error(fsys.err) - return - } + ctx := context.Background() log := slog.New(slog.NewTextHandler(io.Discard, nil)) - b, err := NewTakeout(ctx, fileevent.NewRecorder(log, false), immich.DefaultSupportedMedia, fsys) + b, err := NewTakeout(ctx, fileevent.NewRecorder(log, false), immich.DefaultSupportedMedia, fsys...) if err != nil { t.Error(err) } @@ -130,12 +157,15 @@ func TestBrowse(t *testing.T) { results := []fileResult{} for a := range b.Browse(ctx) { results = append(results, fileResult{name: path.Base(a.FileName), size: a.FileSize, title: a.Title}) + if a.LivePhoto != nil { + results = append(results, fileResult{name: path.Base(a.LivePhoto.FileName), size: a.LivePhoto.FileSize, title: a.LivePhoto.Title}) + } } results = sortFileResult(results) - if !reflect.DeepEqual(results, c.results) { + if !reflect.DeepEqual(results, c.want) { t.Errorf("difference\n") - pretty.Ldiff(t, c.results, results) + pretty.Ldiff(t, c.want, results) } }) } @@ -144,19 +174,19 @@ func TestBrowse(t *testing.T) { func TestAlbums(t *testing.T) { type album map[string][]fileResult tc := []struct { - name string - gen func() *inMemFS - albums album + name string + gen func() []fs.FS + want album }{ { - name: "simpleYear", - gen: simpleYear, - albums: album{}, + name: "simpleYear", + gen: simpleYear, + want: album{}, }, { name: "simpleAlbum", gen: simpleAlbum, - albums: album{ + want: album{ "Album": sortFileResult([]fileResult{ {name: "IMG_8172.jpg", size: 52, title: "IMG_8172.jpg"}, {name: "PXL_20230922_144936660.jpg", size: 10, title: "PXL_20230922_144936660.jpg"}, @@ -166,9 +196,8 @@ func TestAlbums(t *testing.T) { { name: "albumWithoutImage", gen: albumWithoutImage, - albums: album{ + want: album{ "Album": sortFileResult([]fileResult{ - {name: "PXL_20230922_144934440.jpg", size: 15, title: "PXL_20230922_144934440.jpg"}, {name: "PXL_20230922_144936660.jpg", size: 10, title: "PXL_20230922_144936660.jpg"}, }), }, @@ -176,7 +205,7 @@ func TestAlbums(t *testing.T) { { name: "namesIssue39", gen: namesIssue39, - albums: album{ + want: album{ "Album": sortFileResult([]fileResult{ {name: "Backyard_ceremony_wedding_photography_xxxxxxx_m.jpg", size: 1, title: "Backyard_ceremony_wedding_photography_xxxxxxx_magnoliastudios-371.jpg"}, {name: "Backyard_ceremony_wedding_photography_xxxxxxx_m(1).jpg", size: 181, title: "Backyard_ceremony_wedding_photography_xxxxxxx_magnoliastudios-181.jpg"}, @@ -190,11 +219,8 @@ func TestAlbums(t *testing.T) { t.Run(c.name, func(t *testing.T) { ctx := context.Background() fsys := c.gen() - if fsys.err != nil { - t.Error(fsys.err) - return - } - b, err := NewTakeout(ctx, fileevent.NewRecorder(nil, false), immich.DefaultSupportedMedia, fsys) + + b, err := NewTakeout(ctx, fileevent.NewRecorder(nil, false), immich.DefaultSupportedMedia, fsys...) if err != nil { t.Error(err) } @@ -218,10 +244,137 @@ func TestAlbums(t *testing.T) { albums[k] = sortFileResult(al) } - if !reflect.DeepEqual(albums, c.albums) { + if !reflect.DeepEqual(albums, c.want) { t.Errorf("difference\n") - pretty.Ldiff(t, c.albums, albums) + pretty.Ldiff(t, c.want, albums) } }) } } + +func TestArchives(t *testing.T) { + type photo map[string]string + type album map[string][]string + tc := []struct { + name string + gen func() []fs.FS + acceptMissingJSON bool + wantLivePhotos photo + wantAlbum album + wantAsset photo + }{ + { + name: "checkLivePhoto", + gen: checkLivePhoto, + wantAsset: photo{}, + wantLivePhotos: photo{ + "Motion Test/PXL_20231118_035751175.MP.jpg": "Motion Test/PXL_20231118_035751175.MP", + "Motion test/20231227_152817.jpg": "Motion test/20231227_152817.MP4", + }, + wantAlbum: album{}, + }, + { + name: "checkLivePhotoPixil", + gen: checkLivePhotoPixil, + wantAsset: photo{}, + wantLivePhotos: photo{ + "Takeout/Google Photos/2022 - Germany - Private/IMG_4573.HEIC": "Takeout/Google Photos/2022 - Germany - Private/IMG_4573.MP4", + "Takeout/Google Photos/Photos from 2022/IMG_4573.HEIC": "Takeout/Google Photos/Photos from 2022/IMG_4573.MP4", + "Takeout/Google Photos/2022 - Germany/IMG_4573.HEIC": "Takeout/Google Photos/2022 - Germany/IMG_4573.MP4", + }, + wantAlbum: album{ + "2022 - Germany - Private": []string{"IMG_4573.HEIC"}, + "2022 - Germany": []string{"IMG_4573.HEIC"}, + }, + }, + { + name: "checkMissingJSON-No", + gen: checkMissingJSON, + wantAsset: photo{ + "Takeout/Google Photos/Photos from 2022/IMG_4573.HEIC": "", + }, + wantLivePhotos: photo{}, + wantAlbum: album{}, + }, + { + name: "checkMissingJSON-Yes", + gen: checkMissingJSON, + acceptMissingJSON: true, + wantAsset: photo{ + "Takeout/Google Photos/Photos from 2022/IMG_4573.HEIC": "", + "Takeout/Google Foto/Photos from 2016/IMG-20161201-WA0035.jpeg": "", + "Takeout/Google Photos/2022 - Germany - Private/IMG_4553.HEIC": "", + }, + wantLivePhotos: photo{ + "Takeout/Google Photos/2022 - Germany/IMG_1234.HEIC": "Takeout/Google Photos/2022 - Germany/IMG_1234.MP4", + }, + wantAlbum: album{ + "2022 - Germany": []string{"IMG_1234.HEIC"}, + }, + }, + { + name: "checkDuplicates", + gen: checkDuplicates, + wantAsset: photo{ + "Takeout/Google Foto/[E&S] 2016-01-05 - Castello De Albertis e Mostra d/20160105_121621_LLS.jpg": "", + "Takeout/Google Foto/Photos from 2016/20160105_121621_LLS.jpg": "", + "Takeout/Google Foto/2016-01-05 - _3/20160105_121621_LLS.jpg": "", + }, + wantLivePhotos: photo{}, + wantAlbum: album{}, + }, + // { // #405 + // name: "checkMP_405", + // gen: checkMP_405, + // }, + } + for _, c := range tc { + t.Run( + c.name, + func(t *testing.T) { + ctx := context.Background() + fsys := c.gen() + + b, err := NewTakeout(ctx, fileevent.NewRecorder(nil, false), immich.DefaultSupportedMedia, fsys...) + if err != nil { + t.Error(err) + } + b.SetAcceptMissingJSON(c.acceptMissingJSON) + err = b.Prepare(ctx) + if err != nil { + t.Error(err) + } + + livePhotos := photo{} + assets := photo{} + albums := album{} + for a := range b.Browse(ctx) { + if a.LivePhoto != nil { + photo := a.FileName + video := a.LivePhoto.FileName + livePhotos[photo] = video + } else { + assets[a.FileName] = "" + } + for _, al := range a.Albums { + l := albums[al.Title] + l = append(l, path.Base(a.FileName)) + albums[al.Title] = l + } + } + if !reflect.DeepEqual(assets, c.wantAsset) { + t.Errorf("difference assets\n") + pretty.Ldiff(t, c.wantAsset, assets) + } + if !reflect.DeepEqual(livePhotos, c.wantLivePhotos) { + t.Errorf("difference LivePhotos\n") + pretty.Ldiff(t, c.wantLivePhotos, livePhotos) + } + if !reflect.DeepEqual(albums, c.wantAlbum) { + t.Errorf("difference Album\n") + pretty.Ldiff(t, c.wantAlbum, albums) + } + }, + ) + } +} diff --git a/cmd/shared.go b/cmd/shared.go index 390ebbac..46c862e1 100644 --- a/cmd/shared.go +++ b/cmd/shared.go @@ -17,6 +17,7 @@ import ( "github.com/simulot/immich-go/helpers/myflag" "github.com/simulot/immich-go/helpers/tzone" "github.com/simulot/immich-go/immich" + fakeimmich "github.com/simulot/immich-go/internal/fakeImmich" "github.com/simulot/immich-go/ui" "github.com/telemachus/humane" ) @@ -38,6 +39,7 @@ type SharedFlags struct { NoUI bool // Disable user interface JSONLog bool // Enable JSON structured log DebugCounters bool // Enable CSV action counters per file + DebugFileList bool // When true, the file argument is a file wile the list of Takeout files Immich immich.ImmichInterface // Immich client Log *slog.Logger // Logger @@ -94,6 +96,11 @@ func (app *SharedFlags) Start(ctx context.Context) error { app.Jnl = fileevent.NewRecorder(nil, app.DebugCounters) } + if app.DebugFileList { + app.Immich = &fakeimmich.MockedCLient{} + _ = os.Remove(app.LogFile) + } + if app.LogFile != "" { if app.LogWriterCloser == nil { err := configuration.MakeDirForFile(app.LogFile) diff --git a/cmd/upload/e2e_takeout_test.go b/cmd/upload/e2e_takeout_test.go new file mode 100644 index 00000000..9d077989 --- /dev/null +++ b/cmd/upload/e2e_takeout_test.go @@ -0,0 +1,79 @@ +//go:build e2e +// +build e2e + +package upload + +import ( + "context" + "io/fs" + "os" + "path/filepath" + "testing" + + "github.com/simulot/immich-go/cmd" + "github.com/simulot/immich-go/internal/fakefs" +) + +// Simulate a takeout archive with the list of zipped files +func simulate_upload(t *testing.T, zipList string, dateFormat string) { + ic := &icCatchUploadsAssets{ + albums: map[string][]string{}, + } + ctx := context.Background() + + // log := slog.New(slog.NewTextHandler(io.Discard, nil)) + serv := cmd.SharedFlags{ + Immich: ic, + LogLevel: "INFO", + // Jnl: fileevent.NewRecorder(log, false), + // Log: log, + } + + fsOpener := func() ([]fs.FS, error) { + return fakefs.ScanFileList(zipList, dateFormat) + } + os.Remove(filepath.Dir(zipList) + "/debug.log") + args := []string{"-google-photos", "-no-ui", "-debug-counters", "-log-file=" + filepath.Dir(zipList) + "/debug.log"} + + app, err := newCommand(ctx, &serv, args, fsOpener) + if err != nil { + t.Errorf("can't instantiate the UploadCmd: %s", err) + return + } + + err = app.run(ctx) + if err != nil { + t.Errorf("can't run the UploadCmd: %s", err) + return + } +} + +func TestPixilTakeOut(t *testing.T) { + initMyEnv(t) + + simulate_upload(t, myEnv["IMMICH_TESTFILES"]+"/User Files/pixil/list.lst", "01-02-2006 15:04") +} + +func TestPhyl404TakeOut(t *testing.T) { + initMyEnv(t) + + simulate_upload(t, myEnv["IMMICH_TESTFILES"]+"/User Files/Phyl404/list.lst", "2006-01-02 15:04") +} + +func TestPhyl404_2TakeOut(t *testing.T) { + initMyEnv(t) + + simulate_upload(t, myEnv["IMMICH_TESTFILES"]+"/User Files/Phy404#2/list.lst", "2006-01-02 15:04") +} + +func TestSteve81TakeOut(t *testing.T) { + initMyEnv(t) + + simulate_upload(t, myEnv["IMMICH_TESTFILES"]+"/User Files/Steve81/list.list", "2006-01-02 15:04") +} + +func TestMuetyTakeOut(t *testing.T) { + initMyEnv(t) + + simulate_upload(t, myEnv["IMMICH_TESTFILES"]+"/User Files/muety/list.lst", "01-02-2006 15:04") +} diff --git a/cmd/upload/noui.go b/cmd/upload/noui.go index 4344cdf2..3518dafb 100644 --- a/cmd/upload/noui.go +++ b/cmd/upload/noui.go @@ -2,7 +2,10 @@ package upload import ( "context" + "errors" "fmt" + "strings" + "sync/atomic" "time" "github.com/simulot/immich-go/helpers/fileevent" @@ -13,6 +16,8 @@ func (app *UpCmd) runNoUI(ctx context.Context) error { ctx, cancel := context.WithCancelCause(ctx) defer cancel(nil) + var preparationDone atomic.Bool + stopProgress := make(chan any) var maxImmich, currImmich int spinner := []rune{' ', ' ', '.', ' ', ' '} @@ -23,41 +28,37 @@ func (app *UpCmd) runNoUI(ctx context.Context) error { } progressString := func() string { - var s string counts := app.Jnl.GetCounts() + defer func() { + spinIdx++ + if spinIdx == len(spinner) { + spinIdx = 0 + } + }() immichPct := 0 if maxImmich > 0 { immichPct = 100 * currImmich / maxImmich + } else { + immichPct = 100 } - ScannedAssets := counts[fileevent.DiscoveredImage] + counts[fileevent.DiscoveredVideo] - counts[fileevent.DiscoveredDiscarded] - ProcessedAssets := counts[fileevent.Uploaded] + - counts[fileevent.UploadServerError] + - counts[fileevent.UploadNotSelected] + - counts[fileevent.UploadUpgraded] + - counts[fileevent.UploadServerDuplicate] + - counts[fileevent.UploadServerBetter] + - counts[fileevent.DiscoveredDiscarded] + - counts[fileevent.AnalysisLocalDuplicate] if app.GooglePhotos { - gpPct := 0 - upPct := 0 - if ScannedAssets > 0 { - gpPct = int(100 * counts[fileevent.AnalysisAssociatedMetadata] / ScannedAssets) - } - if counts[fileevent.AnalysisAssociatedMetadata] > 0 { - upPct = int(100 * ProcessedAssets / counts[fileevent.AnalysisAssociatedMetadata]) + gpTotal := app.Jnl.TotalAssets() + gpProcessed := app.Jnl.TotalProcessedGP() + + gpPercent := int(100 * gpProcessed / gpTotal) + upProcessed := int64(0) + if preparationDone.Load() { + upProcessed = app.Jnl.TotalProcessed() } + upTotal := app.Jnl.TotalAssets() + upPercent := 100 * upProcessed / upTotal - s = fmt.Sprintf("\rImmich read %d%%, Google Photos Analysis: %d%%, Upload errors: %d, Uploaded %d%% %s", immichPct, gpPct, counts[fileevent.UploadServerError], upPct, string(spinner[spinIdx])) - } else { - s = fmt.Sprintf("\rImmich read %d%%, Processed %d, Upload errors: %d, Uploaded %d %s", immichPct, ProcessedAssets, counts[fileevent.UploadServerError], counts[fileevent.Uploaded], string(spinner[spinIdx])) + return fmt.Sprintf("\rImmich read %d%%, Google Photos Analysis: %d%%, Upload errors: %d, Uploaded %d%% %s", + immichPct, gpPercent, counts[fileevent.UploadServerError], upPercent, string(spinner[spinIdx])) } - spinIdx++ - if spinIdx == len(spinner) { - spinIdx = 0 - } - return s + + return fmt.Sprintf("\rImmich read %d%%, Upload errors: %d, Uploaded %d %s", immichPct, counts[fileevent.UploadServerError], counts[fileevent.Uploaded], string(spinner[spinIdx])) } uiGrp := errgroup.Group{} @@ -111,10 +112,25 @@ func (app *UpCmd) runNoUI(ctx context.Context) error { return err } } + preparationDone.Store(true) err = app.uploadLoop(ctx) if err != nil { cancel(err) } + + counts := app.Jnl.GetCounts() + messages := strings.Builder{} + if counts[fileevent.Error]+counts[fileevent.UploadServerError] > 0 { + messages.WriteString("Some errors have occurred. Look at the log file for details\n") + } + if app.GooglePhotos && counts[fileevent.AnalysisMissingAssociatedMetadata] > 0 { + messages.WriteString(fmt.Sprintf("\n%d JSON files are missing.\n", counts[fileevent.AnalysisMissingAssociatedMetadata])) + messages.WriteString("- have you processed all takeout parts together?\n") + messages.WriteString("- ask for another takeout, or ask one year at a time.\n") + } + if messages.Len() > 0 { + cancel(errors.New(messages.String())) + } close(stopProgress) return err }) diff --git a/cmd/upload/ui.go b/cmd/upload/ui.go index ee312060..18fb09bb 100644 --- a/cmd/upload/ui.go +++ b/cmd/upload/ui.go @@ -6,6 +6,7 @@ import ( "fmt" "io" "log/slog" + "strings" "sync/atomic" "time" @@ -51,6 +52,7 @@ func (app *UpCmd) runUI(ctx context.Context) error { var preparationDone atomic.Bool var uploadDone atomic.Bool var uiGroup errgroup.Group + var messages strings.Builder uiApp.SetRoot(pages, true) @@ -61,9 +63,7 @@ func (app *UpCmd) runUI(ctx context.Context) error { } } - modal := newModal() pages.AddPage("ui", ui.screen, true, true) - pages.AddPage("modal", modal, true, false) // handle Ctrl+C and Ctrl+Q uiApp.SetInputCapture(func(event *tcell.EventKey) *tcell.EventKey { @@ -128,15 +128,13 @@ func (app *UpCmd) runUI(ctx context.Context) error { ui.getCountView(c, counts[c]) } if app.GooglePhotos { - ui.immichPrepare.SetMaxValue(int(counts[fileevent.DiscoveredImage] + counts[fileevent.DiscoveredVideo])) - ui.immichPrepare.SetValue(int(counts[fileevent.AnalysisAssociatedMetadata])) - - ui.immichUpload.SetMaxValue(int(counts[fileevent.DiscoveredImage] + counts[fileevent.DiscoveredVideo])) - ui.immichUpload.SetValue(int(counts[fileevent.UploadNotSelected] + - counts[fileevent.UploadUpgraded] + - counts[fileevent.UploadServerDuplicate] + - counts[fileevent.UploadServerBetter] + - counts[fileevent.Uploaded])) + ui.immichPrepare.SetMaxValue(int(app.Jnl.TotalAssets())) + ui.immichPrepare.SetValue(int(app.Jnl.TotalProcessedGP())) + + if preparationDone.Load() { + ui.immichUpload.SetMaxValue(int(app.Jnl.TotalAssets())) + } + ui.immichUpload.SetValue(int(app.Jnl.TotalProcessed())) } }) } @@ -195,9 +193,21 @@ func (app *UpCmd) runUI(ctx context.Context) error { return context.Cause(ctx) } uploadDone.Store(true) + counts := app.Jnl.GetCounts() + if counts[fileevent.Error]+counts[fileevent.UploadServerError] > 0 { + messages.WriteString("Some errors have occurred. Look at the log file for details\n") + } + if app.GooglePhotos && counts[fileevent.AnalysisMissingAssociatedMetadata] > 0 { + messages.WriteString(fmt.Sprintf("\n%d JSON files are missing.\n", counts[fileevent.AnalysisMissingAssociatedMetadata])) + messages.WriteString("- have you processed all takeout parts together?\n") + messages.WriteString("- ask for another takeout, or ask one year at a time.\n") + } + modal := newModal(messages.String()) + pages.AddPage("modal", modal, true, false) // upload is done! pages.ShowPage("modal") + return err }) @@ -209,10 +219,15 @@ func (app *UpCmd) runUI(ctx context.Context) error { // Time to leave app.Jnl.Report() + if messages.Len() > 0 { + return (errors.New(messages.String())) + } return err } -func newModal() tview.Primitive { +func newModal(message string) tview.Primitive { + message += "\nYou can quit the program safely.\n\nPress the [enter] key to exit." + lines := strings.Count(message, "\n") // Returns a new primitive which puts the provided primitive in the center and // sets its size to the given width and height. modal := func(p tview.Primitive, width, height int) tview.Primitive { @@ -224,12 +239,12 @@ func newModal() tview.Primitive { AddItem(nil, 0, 1, false), width, 1, true). AddItem(nil, 0, 1, false) } - text := tview.NewTextView().SetText("\nYou can quit the program safely.\n\nPress the [enter] key to exit.").SetTextAlign(tview.AlignCenter) + text := tview.NewTextView().SetText(message) box := tview.NewBox(). SetBorder(true). SetTitle("Upload completed") text.Box = box - return modal(text, 40, 7) + return modal(text, 80, 2+lines) } func newUI(ctx context.Context, app *UpCmd) *uiPage { diff --git a/cmd/upload/upload.go b/cmd/upload/upload.go index ed182ffc..906555cf 100644 --- a/cmd/upload/upload.go +++ b/cmd/upload/upload.go @@ -27,6 +27,7 @@ import ( "github.com/simulot/immich-go/helpers/namematcher" "github.com/simulot/immich-go/helpers/stacking" "github.com/simulot/immich-go/immich" + "github.com/simulot/immich-go/internal/fakefs" ) type UpCmd struct { @@ -55,6 +56,7 @@ type UpCmd struct { StackBurst bool // Stack burst (Default: TRUE) DiscardArchived bool // Don't import archived assets (Default: FALSE) WhenNoDate string // When the date can't be determined use the FILE's date or NOW (default: FILE) + ForceUploadWhenNoJSON bool // Some takeout don't supplies all JSON. When true, files are uploaded without any additional metadata BannedFiles namematcher.List // List of banned file name patterns BrowserConfig Configuration @@ -70,7 +72,7 @@ type UpCmd struct { } func UploadCommand(ctx context.Context, common *cmd.SharedFlags, args []string) error { - app, err := newCommand(ctx, common, args) + app, err := newCommand(ctx, common, args, nil) if err != nil { return err } @@ -80,7 +82,9 @@ func UploadCommand(ctx context.Context, common *cmd.SharedFlags, args []string) return app.run(ctx) } -func newCommand(ctx context.Context, common *cmd.SharedFlags, args []string) (*UpCmd, error) { +type fsOpener func() ([]fs.FS, error) + +func newCommand(ctx context.Context, common *cmd.SharedFlags, args []string, fsOpener fsOpener) (*UpCmd, error) { var err error cmd := flag.NewFlagSet("upload", flag.ExitOnError) @@ -149,14 +153,14 @@ func newCommand(ctx context.Context, common *cmd.SharedFlags, args []string) (*U cmd.BoolFunc( "create-stacks", - "Stack jpg/raw or bursts (default TRUE)", myflag.BoolFlagFn(&app.CreateStacks, true)) + "Stack jpg/raw or bursts (default FALSE)", myflag.BoolFlagFn(&app.CreateStacks, false)) cmd.BoolFunc( "stack-jpg-raw", - "Control the stacking of jpg/raw photos (default TRUE)", myflag.BoolFlagFn(&app.StackJpgRaws, true)) + "Control the stacking of jpg/raw photos (default TRUE)", myflag.BoolFlagFn(&app.StackJpgRaws, false)) cmd.BoolFunc( "stack-burst", - "Control the stacking bursts (default TRUE)", myflag.BoolFlagFn(&app.StackBurst, true)) + "Control the stacking bursts (default TRUE)", myflag.BoolFlagFn(&app.StackBurst, false)) // cmd.BoolVar(&app.Delete, "delete", false, "Delete local assets after upload") @@ -170,11 +174,27 @@ func newCommand(ctx context.Context, common *cmd.SharedFlags, args []string) (*U cmd.Var(&app.BannedFiles, "exclude-files", "Ignore files based on a pattern. Case insensitive. Add one option for each pattern do you need.") + cmd.BoolVar(&app.ForceUploadWhenNoJSON, "upload-when-missing-JSON", app.ForceUploadWhenNoJSON, "when true, photos are upload even without associated JSON file.") + cmd.BoolVar(&app.DebugFileList, "debug-file-list", app.DebugFileList, "Check how the your file list would be processed") + err = cmd.Parse(args) if err != nil { return nil, err } + if app.DebugFileList { + if len(cmd.Args()) < 2 { + return nil, fmt.Errorf("the option -debug-file-list requires a file name and a date format") + } + app.LogFile = strings.TrimSuffix(cmd.Arg(0), filepath.Ext(cmd.Arg(0))) + ".log" + _ = os.Remove(app.LogFile) + + fsOpener = func() ([]fs.FS, error) { + return fakefs.ScanFileList(cmd.Arg(0), cmd.Arg(1)) + } + } else { + } + app.WhenNoDate = strings.ToUpper(app.WhenNoDate) switch app.WhenNoDate { case "FILE", "NOW": @@ -188,7 +208,12 @@ func newCommand(ctx context.Context, common *cmd.SharedFlags, args []string) (*U return nil, err } - app.fsyss, err = fshelper.ParsePath(cmd.Args(), app.GooglePhotos) + if fsOpener == nil { + fsOpener = func() ([]fs.FS, error) { + return fshelper.ParsePath(cmd.Args()) + } + } + app.fsyss, err = fsOpener() if err != nil { return nil, err } @@ -459,6 +484,9 @@ func (app *UpCmd) handleAsset(ctx context.Context, a *browser.LocalAssetFile) er app.Jnl.Record(ctx, fileevent.UploadServerDuplicate, a, a.FileName) } else { app.Jnl.Record(ctx, fileevent.AnalysisLocalDuplicate, a, a.FileName) + if a.LivePhoto != nil { + app.Jnl.Record(ctx, fileevent.AnalysisLocalDuplicate, a, a.LivePhoto.FileName) + } } app.manageAssetAlbum(ctx, advice.ServerAsset.ID, a, advice) diff --git a/cpu.prof b/cpu.prof new file mode 100644 index 00000000..829e26ee Binary files /dev/null and b/cpu.prof differ diff --git a/docs/google-takeout.md b/docs/google-takeout.md index d1ff5554..d662b7e8 100644 --- a/docs/google-takeout.md +++ b/docs/google-takeout.md @@ -72,17 +72,18 @@ takeout-20240712T112341Z-010.zip: ``` -## Some key names are spelled in the user language +## Some key file names are spelled in the user language -| Language | Google Photos folder name | Album's metadata | -| ---------- | ------------------------- | ---------------- | -| US English | Google Photos | metadata.json | -| French | Google Photos | métadonnées.json | -| Italian | Google Foto | | -| Slovak | Fotky Google | metadáta.json | +| Language | Google Photos folder | Album's metadata | Edited photo name | +| ---------- | -------------------- | ---------------- | ----------------- | +| US English | Google Photos | metadata.json | | +| French | Google Photos | métadonnées.json | \*-modifié.\* | +| Italian | Google Foto | metadati.json | \*-modificato.\* | +| Slovak | Fotky Google | metadáta.json | | +| German | Google Fotos | Metadaten.json | \*-bearbeitet.\* | # What if you have problems with a takeout archive? -Please open an issue with details. You cna share your files using Discord DM @`simulot`. +Please open an issue with details. You cna share your files using Discord DM `@simulot`. I'll check if I can improve the program. Sometime a manual import is the best option. diff --git a/docs/how-to-send-debug-data.md b/docs/how-to-send-debug-data.md new file mode 100644 index 00000000..992a2e33 --- /dev/null +++ b/docs/how-to-send-debug-data.md @@ -0,0 +1,87 @@ +# How to share data with the developer? + +The structure of the takeout archive can be weird enough to get `Immich-go` confused. + + +In most of the cases, the list of files is sufficient for trouble-shooting the problem. +This size of the list is much smaller than the full archive and contains enough information for simulating the import process. + +This list reveals only the files's name and size, and the albums' name. + +If you agree, you can share it with me via a DM on discord @simulot. + + + +## Get the file list from a zip takeout + +```sh +for f in *.zip; do echo "$f:"; unzip -l $f; done >list.lst +``` + +This produces a file like this: +``` +takeout-20240523T170453Z-001.zip: +Archive: takeout-20240523T170453Z-001.zip + Length Date Time Name +--------- ---------- ----- ---- + 800432 2024-05-23 19:31 Takeout/Google Photos/Photos from 2018/IMG_8135.JPG + 1166223 2024-05-23 19:31 Takeout/Google Photos/Photos from 2018/IMG_8133.JPG + 17132148 2024-05-23 19:31 Takeout/Google Photos/Photos from 2018/VID_20180819_191954.mp4 + 604784 2024-05-23 19:31 Takeout/Google Photos/Photos from 2018/IMG_8131.JPG + 645224 2024-05-23 19:31 Takeout/Google Photos/Photos from 2018/IMG_8130.JPG + 188804 2024-05-23 19:31 Takeout/Google Photos/Photos from 2018/IMG_8132.JPG + 375981 2024-05-23 19:31 Takeout/Google Photos/Photos from 2018/IMG_8129.JPG + 478073 2024-05-23 19:31 Takeout/Google Photos/Photos from 2018/IMG_8128.JPG + 2047609 2024-05-23 19:31 Takeout/Google Photos/Photos from 2018/IMG_8125.JPG + 2250833 2024-05-23 19:31 Takeout/Google Photos/Photos from 2018/IMG_8124.JPG + 429040 2024-05-23 19:31 Takeout/Google Photos/Photos from 2018/IMG_8120.JPG + 908856 2024-05-23 19:31 Takeout/Google Photos/Photos from 2018/IMG_8117.JPG + 699546 2024-05-23 19:31 Takeout/Google Photos/Photos from 2018/IMG_8118.JPG + 625635 2024-05-23 19:31 Takeout/Google Photos/Photos from 2018/IMG_8115.JPG + 1006873 2024-05-23 19:31 Takeout/Google Photos/Photos from 2018/IMG_8116.JPG + 499507 2024-05-23 19:31 Takeout/Google Photos/Photos from 2018/IMG_8114.JPG + 43189565 2024-05-23 19:31 Takeout/Google Photos/Photos from 2018/VID_20180819_192245.mp4 + 541875 2024-05-23 19:32 Takeout/Google Photos/Photos from 2018/IMG_8112.JPG + 503405 2024-05-23 19:32 Takeout/Google Photos/Photos from 2018/IMG_8113.JPG + 1070437 2024-05-23 19:32 Takeout/Google Photos/Photos from 2018/IMG_8111.JPG + 583809 2024-05-23 19:32 Takeout/Google Photos/Photos from 2018/IMG_8110.JPG + 808994 2024-05-23 19:32 Takeout/Google Photos/Photos from 2018/IMG_20180718_163816.jpg + 798787 2024-05-23 19:32 Takeout/Google Photos/Photos from 2018/IMG_20180718_163817.jpg +... +``` + + + +## Get the file list from a tgz takeout + +```sh +for f in *.tgz; do echo "$f:"; tar -tzvf $f; done >list.lst +``` + +This produces a file like this: +``` +takeout-20231209T153001Z-001.tgz: +-rw-r--r-- 0/0 3987330 2023-12-09 16:30 Takeout/Google Photos/Photos from 2023/PXL_20231207_192201288.PORTRAIT.jpg +-rw-r--r-- 0/0 3825143 2023-12-09 16:30 Takeout/Google Photos/Photos from 2023/PXL_20231207_192200378.PORTRAIT.jpg +-rw-r--r-- 0/0 838 2023-12-09 16:30 Takeout/Google Photos/Photos from 2023/PXL_20231207_202525504.jpg.json +-rw-r--r-- 0/0 4136113 2023-12-09 16:30 Takeout/Google Photos/Photos from 2023/PXL_20231207_192157945.PORTRAIT.jpg +-rw-r--r-- 0/0 2817334 2023-12-09 16:30 Takeout/Google Photos/Photos from 2023/PXL_20231207_192146687.PORTRAIT.jpg +-rw-r--r-- 0/0 838 2023-12-09 16:30 Takeout/Google Photos/Photos from 2023/PXL_20231207_202513366.jpg.json +-rw-r--r-- 0/0 827 2023-12-09 16:30 Takeout/Google Photos/Photos from 2023/PXL_20231209_074450784.LS.mp4.json +-rw-r--r-- 0/0 1453060 2023-12-09 16:30 Takeout/Google Photos/Photos from 2023/PXL_20231207_202525504.jpg +-rw-r--r-- 0/0 819 2023-12-09 16:30 Takeout/Google Photos/Photos from 2023/PXL_20231207_192200378.PORTRAIT.jpg.json +-rw-r--r-- 0/0 849 2023-12-09 16:30 Takeout/Google Photos/Photos from 2023/PXL_20231207_192157945.PORTRAIT.jpg.json +-rw-r--r-- 0/0 2852580 2023-12-09 16:30 Takeout/Google Photos/Photos from 2023/PXL_20231207_192125032.PORTRAIT.jpg +-rw-r--r-- 0/0 827 2023-12-09 16:30 Takeout/Google Photos/Photos from 2023/PXL_20231209_073951854.LS.mp4.json +-rw-r--r-- 0/0 3046592 2023-12-09 16:30 Takeout/Google Photos/Photos from 2023/PXL_20231207_192127213.PORTRAIT.jpg +-rw-r--r-- 0/0 684979 2023-12-09 16:30 Takeout/Google Photos/Photos from 2023/PXL_20231209_074450784.LS.mp4 +-rw-r--r-- 0/0 2638469 2023-12-09 16:30 Takeout/Google Photos/Photos from 2023/PXL_20231207_192128472.PORTRAIT.jpg +-rw-r--r-- 0/0 819 2023-12-09 16:30 Takeout/Google Photos/Photos from 2023/PXL_20231207_192201288.PORTRAIT.jpg.json +-rw-r--r-- 0/0 1046367 2023-12-09 16:30 Takeout/Google Photos/Photos from 2023/PXL_20231207_202513366.jpg +-rw-r--r-- 0/0 867 2023-12-09 16:30 Takeout/Google Photos/Photos from 2023/PXL_20231207_192128472.PORTRAIT.jpg.json +-rw-r--r-- 0/0 602708 2023-12-09 16:30 Takeout/Google Photos/Photos from 2023/PXL_20231207_191742033.jpg +-rw-r--r-- 0/0 867 2023-12-09 16:30 Takeout/Google Photos/Photos from 2023/PXL_20231207_192127213.PORTRAIT.jpg.json +-rw-r--r-- 0/0 867 2023-12-09 16:30 Takeout/Google Photos/Photos from 2023/PXL_20231207_192146687.PORTRAIT.jpg.json +-rw-r--r-- 0/0 867 2023-12-09 16:30 Takeout/Google Photos/Photos from 2023/PXL_20231207_192125032.PORTRAIT.jpg.json +... +``` \ No newline at end of file diff --git a/docs/releases.md b/docs/releases.md index 7981daf1..7ce60380 100644 --- a/docs/releases.md +++ b/docs/releases.md @@ -5,6 +5,74 @@ - [Github Sponsor page](https://github.com/sponsors/simulot) - [paypal donor page](https://www.paypal.com/donate/?hosted_button_id=VGU2SQE88T2T4) +## Release next + +### TO DO +- [ ] Counters / missing assets GooglePhotos + - [X] [#390](https://github.com/simulot/immich-go/issues/390) + - [X] [#376](https://github.com/simulot/immich-go/issues/376) + - [X] [#401](https://github.com/simulot/immich-go/issues/401) + - [X] [#402](https://github.com/simulot/immich-go/issues/402) Problem with images with same name + - [ ] [#405](https://github.com/simulot/immich-go/issues/405) MP~2 files + - [X] Some files are not matched (PIXIL) + - [X] Check .MP.JPG + - [X] Check asset in multiple albums + - [ ] Phyl404 case + - [X] Ziplist reader broken (Phyl404) + - [X] Some file aren't matched (Phyl404) + - [X] fix gp solving percent (Phyl404) + - [ ] [#402](https://github.com/simulot/immich-go/issues/402) Steve81 issue + - [X] wrong album + - [X] Add message about missing JSON UI and NOUI + - [ ] Deactivate stack option + - [ ] Performances + - [X] matchDuplicateInYear 27% + - [X] SupportedMedia.IsExtensionPrefix + - [ ] remove break points + - [ ] run tests +- [ ] Report connection errors + - [ ] [#395](https://github.com/simulot/immich-go/issues/395) + - [ ] [#396](https://github.com/simulot/immich-go/issues/396) + - [ ] [#393](https://github.com/simulot/immich-go/issues/393) +- [ ] Creation date incorrect + - [X] [#392](https://github.com/simulot/immich-go/issues/392) + - [ ] [#397](https://github.com/simulot/immich-go/issues/397) + + + + +### Refactoring the Google Photos import another time +Lot of users have reported inconsistencies in upload counters. Each user case a different, and the takeout structure varies a bit. +In order to debug those cases, I have developed a way to simulate the takeout import using only the the file list. Read [how to send debug data](/docs/how-to-send-debug-data.md) without sharing photos. + + +### Option to force the upload of images despite the lack of JSON +Each image in a takeout is supposed to come with A JSON file giving the date of capture and the GPS coordinate. There a few reason for this: +1. The original file is copied, modified... and sometime there ins't a JSON for all versions +2. JSON aren't in the same ZIP file than the image, and only one part of the takeout is processed +3. The takeout misses a bunch of JSON + +When asking another takeout isn't an option, it's possible to force the upload of photos with no JSON. Use the option `-upload-when-missing-JSON` + +### The stack function is disabled +The stack function need to be improved [#399](https://github.com/simulot/immich-go/issues/399), [#345](https://github.com/simulot/immich-go/issues/345), [#235](https://github.com/simulot/immich-go/issues/235) +Meanwhile, it is disabled by default. You can enable it using the option `-create-stacks=TRUE`. + + + + +### fixes: +- [#376](https://github.com/simulot/immich-go/issues/376) errors when uploading are disturbing the the % of the progression +- files with same path and name, but in different part of the takeout file set was forgotten in duplicate counters +- iPhone's Live photos recognition when the name is duplicated: ex IMG_2710(1).MP4 and IMG_2710(1).HEIC +- Missing a file when a directory contain several files with the same name, but of a different type. Ex: IMG_0170.HEIC, IMG_0170.JPG +- Live videos attached to duplicated photos are now counted as duplicate as well, making the final report more relevant +- [#402](https://github.com/simulot/immich-go/issues/402) Wrong album assignment for images with the same name +- [#390](https://github.com/simulot/immich-go/issues/390) Question: report shows way less images uploaded than scanned +- [#376](https://github.com/simulot/immich-go/issues/376) errors when uploading are disturbing the the % of the progression +- [#401](https://github.com/simulot/immich-go/issues/401) Add an option to import images/movies even if there is no JSON file in the takeout + + ## Release 0.20.1 ### changes diff --git a/helpers/fileevent/fileevents.go b/helpers/fileevent/fileevents.go index 2026a31e..aab3c8c9 100644 --- a/helpers/fileevent/fileevents.go +++ b/helpers/fileevent/fileevents.go @@ -221,3 +221,25 @@ func (r *Recorder) WriteFileCounts(w io.Writer) error { } return nil } + +func (r *Recorder) TotalAssets() int64 { + return atomic.LoadInt64(&r.counts[DiscoveredImage]) + atomic.LoadInt64(&r.counts[DiscoveredVideo]) +} + +func (r *Recorder) TotalProcessedGP() int64 { + return atomic.LoadInt64(&r.counts[AnalysisAssociatedMetadata]) + + atomic.LoadInt64(&r.counts[AnalysisMissingAssociatedMetadata]) + + atomic.LoadInt64(&r.counts[DiscoveredDiscarded]) +} + +func (r *Recorder) TotalProcessed() int64 { + return atomic.LoadInt64(&r.counts[Uploaded]) + + atomic.LoadInt64(&r.counts[UploadServerError]) + + atomic.LoadInt64(&r.counts[UploadNotSelected]) + + atomic.LoadInt64(&r.counts[UploadUpgraded]) + + atomic.LoadInt64(&r.counts[UploadServerDuplicate]) + + atomic.LoadInt64(&r.counts[UploadServerBetter]) + + atomic.LoadInt64(&r.counts[DiscoveredDiscarded]) + + atomic.LoadInt64(&r.counts[AnalysisLocalDuplicate]) + + atomic.LoadInt64(&r.counts[AnalysisMissingAssociatedMetadata]) +} diff --git a/helpers/fshelper/globwalkfs.go b/helpers/fshelper/globwalkfs.go index e595995d..1a841fde 100644 --- a/helpers/fshelper/globwalkfs.go +++ b/helpers/fshelper/globwalkfs.go @@ -1,6 +1,7 @@ package fshelper import ( + "fmt" "io/fs" "os" "path" @@ -108,7 +109,7 @@ func (gw GlobWalkFS) ReadDir(name string) ([]fs.DirEntry, error) { } entries, err := fs.ReadDir(gw.rootFS, name) if err != nil { - return nil, err + return nil, fmt.Errorf("ReadDir %s: %w", name, err) } returned := []fs.DirEntry{} diff --git a/helpers/fshelper/parseArgs.go b/helpers/fshelper/parseArgs.go index fff24059..8af89c70 100644 --- a/helpers/fshelper/parseArgs.go +++ b/helpers/fshelper/parseArgs.go @@ -16,7 +16,7 @@ import ( // // TODO: Implement a tgz reader for non google-photos archives -func ParsePath(args []string, googlePhoto bool) ([]fs.FS, error) { +func ParsePath(args []string) ([]fs.FS, error) { var errs error fsyss := []fs.FS{} diff --git a/immich/client.go b/immich/client.go index aef111b5..97b107ac 100644 --- a/immich/client.go +++ b/immich/client.go @@ -7,7 +7,10 @@ import ( "io" "net/http" "os" + "slices" + "sort" "strings" + "sync" "time" ) @@ -223,16 +226,24 @@ func (sm SupportedMedia) IsMedia(ext string) bool { return t == TypeVideo || t == TypeImage } +var ( + _supportedExtension []string + initSupportedExtion sync.Once +) + func (sm SupportedMedia) IsExtensionPrefix(ext string) bool { - ext = strings.ToLower(ext) - for e, t := range sm { - if t == TypeVideo || t == TypeImage { - if ext == e[:len(e)-1] { - return true - } + initSupportedExtion.Do(func() { + _supportedExtension = make([]string, len(sm)) + i := 0 + for k := range sm { + _supportedExtension[i] = k[:len(k)-2] + i++ } - } - return false + sort.Strings(_supportedExtension) + }) + ext = strings.ToLower(ext) + _, b := slices.BinarySearch(_supportedExtension, ext) + return b } func (sm SupportedMedia) IsIgnoredExt(ext string) bool { diff --git a/immich/client_test.go b/immich/client_test.go new file mode 100644 index 00000000..0e20511f --- /dev/null +++ b/immich/client_test.go @@ -0,0 +1,30 @@ +package immich + +import "testing" + +/* +baseline + +goos: linux +goarch: amd64 +pkg: github.com/simulot/immich-go/immich +cpu: Intel(R) Core(TM) i7-10750H CPU @ 2.60GHz +Benchmark_IsExtensionPrefix-12 4096238 297.3 ns/op 3 B/op 1 allocs/op +PASS +ok github.com/simulot/immich-go/immich 1.518s + +goos: linux +goarch: amd64 +pkg: github.com/simulot/immich-go/immich +cpu: Intel(R) Core(TM) i7-10750H CPU @ 2.60GHz +Benchmark_IsExtensionPrefix-12 16536936 72.85 ns/op 3 B/op 1 allocs/op +PASS +ok github.com/simulot/immich-go/immich 1.283s +*/ +func Benchmark_IsExtensionPrefix(b *testing.B) { + sm := DefaultSupportedMedia + sm.IsExtensionPrefix(".JP") + for i := 0; i < b.N; i++ { + sm.IsExtensionPrefix(".JP") + } +} diff --git a/internal/fakeImmich/immich.go b/internal/fakeImmich/immich.go new file mode 100644 index 00000000..dd06a72f --- /dev/null +++ b/internal/fakeImmich/immich.go @@ -0,0 +1,97 @@ +package fakeimmich + +import ( + "context" + "io" + + "github.com/simulot/immich-go/browser" + "github.com/simulot/immich-go/immich" +) + +type MockedCLient struct{} + +func (c *MockedCLient) GetAllAssetsWithFilter(context.Context, func(*immich.Asset) error) error { + return nil +} + +func (c *MockedCLient) AssetUpload(context.Context, *browser.LocalAssetFile) (immich.AssetResponse, error) { + return immich.AssetResponse{}, nil +} + +func (c *MockedCLient) DeleteAssets(context.Context, []string, bool) error { + return nil +} + +func (c *MockedCLient) GetAllAlbums(context.Context) ([]immich.AlbumSimplified, error) { + return nil, nil +} + +func (c *MockedCLient) AddAssetToAlbum(context.Context, string, []string) ([]immich.UpdateAlbumResult, error) { + return nil, nil +} + +func (c *MockedCLient) CreateAlbum(context.Context, string, string, []string) (immich.AlbumSimplified, error) { + return immich.AlbumSimplified{}, nil +} + +func (c *MockedCLient) UpdateAssets(ctx context.Context, ids []string, isArchived bool, isFavorite bool, latitude float64, longitude float64, removeParent bool, stackParentID string) error { + return nil +} + +func (c *MockedCLient) StackAssets(ctx context.Context, cover string, ids []string) error { + return nil +} + +func (c *MockedCLient) UpdateAsset(ctx context.Context, id string, a *browser.LocalAssetFile) (*immich.Asset, error) { + return nil, nil +} + +func (c *MockedCLient) EnableAppTrace(w io.Writer) {} + +func (c *MockedCLient) GetServerStatistics(ctx context.Context) (immich.ServerStatistics, error) { + return immich.ServerStatistics{}, nil +} + +func (c *MockedCLient) PingServer(ctx context.Context) error { + return nil +} + +func (c *MockedCLient) SetDeviceUUID(string) {} + +func (c *MockedCLient) SetEndPoint(string) {} + +func (c *MockedCLient) ValidateConnection(ctx context.Context) (immich.User, error) { + return immich.User{}, nil +} + +func (c *MockedCLient) GetAssetAlbums(ctx context.Context, id string) ([]immich.AlbumSimplified, error) { + return nil, nil +} + +func (c *MockedCLient) GetAllAssets(ctx context.Context) ([]*immich.Asset, error) { + return nil, nil +} + +func (c *MockedCLient) DeleteAlbum(ctx context.Context, id string) error { + return nil +} + +func (c *MockedCLient) SupportedMedia() immich.SupportedMedia { + return immich.DefaultSupportedMedia +} + +func (c *MockedCLient) GetAssetStatistics(ctx context.Context) (immich.UserStatistics, error) { + return immich.UserStatistics{ + Images: 1, + Videos: 1, + Total: 1, + }, nil +} + +func (c *MockedCLient) GetJobs(ctx context.Context) (map[string]immich.Job, error) { + return nil, nil +} + +func (c *MockedCLient) GetAlbumInfo(context.Context, string, bool) (immich.AlbumContent, error) { + return immich.AlbumContent{}, nil +} diff --git a/internal/fakefs/TESTDATA/one.lst b/internal/fakefs/TESTDATA/one.lst new file mode 100644 index 00000000..bbeb319c --- /dev/null +++ b/internal/fakefs/TESTDATA/one.lst @@ -0,0 +1,9 @@ +takeout-20240525T201456Z-003.zip: +Archive: takeout-20240525T201456Z-003.zip + Length Date Time Name +--------- ---------- ----- ---- +245068101 2024-05-25 22:15 Takeout/Google Photos/Garros 19 Juillet 2018/Bebop2_20180719203057+0200.mp4 +221047335 2024-05-25 22:15 Takeout/Google Photos/Garros 19 Juillet 2018/Bebop2_20180719185840+0200.mp4 +229274490 2024-05-25 22:15 Takeout/Google Photos/Garros 19 Juillet 2018/Bebop2_20180719183450+0200.mp4 +--------- ------- +695389926 3 files diff --git a/internal/fakefs/TESTDATA/small.lst b/internal/fakefs/TESTDATA/small.lst new file mode 100644 index 00000000..50ae0612 --- /dev/null +++ b/internal/fakefs/TESTDATA/small.lst @@ -0,0 +1,986 @@ +takeout-20240525T201456Z-001.zip: +Archive: takeout-20240525T201456Z-001.zip + Length Date Time Name +--------- ---------- ----- ---- + 425704 2024-05-25 22:15 Takeout/Google Photos/Guillaumes 2018/IMG_8213.JPG + 307 2018-07-28 10:24 Takeout/Google Photos/Guillaumes 2018/métadonnées.json + 2754273 2024-05-25 22:15 Takeout/Google Photos/Guillaumes 2018/IMG_20180725_102133.jpg + 164272 2024-05-25 22:15 Takeout/Google Photos/Guillaumes 2018/IMG_8416.JPG + 748 2024-05-25 22:15 Takeout/Google Photos/Guillaumes 2018/Bebop2_20180723180057+0200.m4v.json + 730 2024-05-25 22:15 Takeout/Google Photos/Guillaumes 2018/IMG_8416.JPG.json + 731 2024-05-25 22:15 Takeout/Google Photos/Guillaumes 2018/IMG_8213.JPG.json + 775 2024-05-25 22:15 Takeout/Google Photos/Guillaumes 2018/IMG_20180725_102133.jpg.json + 139865 2024-05-25 22:15 Takeout/Google Photos/🇵🇹 Lisbonne ❤️ en famille 👨‍👩‍👦‍👦/✈️ DSC04119.jpg + 736 2024-05-25 22:15 Takeout/Google Photos/🇵🇹 Lisbonne ❤️ en famille 👨‍👩‍👦‍👦/✈️ DSC04119.jpg.json + 954 2024-05-25 22:15 Takeout/Google Photos/🇵🇹 Lisbonne ❤️ en famille 👨‍👩‍👦‍👦/😀😃😄😁😆😅😂🤣🥲☺️😊😇🙂🙃😉😌😍🥰😘😗😙😚😋.json + 353 2023-08-21 19:24 Takeout/Google Photos/🇵🇹 Lisbonne ❤️ en famille 👨‍👩‍👦‍👦/métadonnées.json + 2021088 2024-05-25 22:15 Takeout/Google Photos/🇵🇹 Lisbonne ❤️ en famille 👨‍👩‍👦‍👦/IMG_1763.HEIC + 145804 2024-05-25 22:15 Takeout/Google Photos/🇵🇹 Lisbonne ❤️ en famille 👨‍👩‍👦‍👦/😀😃😄😁😆😅😂🤣🥲☺️😊😇🙂🙃😉😌😍🥰😘😗😙😚😋😛.jpg + 845 2024-05-25 22:15 Takeout/Google Photos/🇵🇹 Lisbonne ❤️ en famille 👨‍👩‍👦‍👦/PXL_20230813_045312704.jpg.json + 845 2024-05-25 22:15 Takeout/Google Photos/🇵🇹 Lisbonne ❤️ en famille 👨‍👩‍👦‍👦/PXL_20230813_045318279.jpg.json + 2548657 2024-05-25 22:15 Takeout/Google Photos/🇵🇹 Lisbonne ❤️ en famille 👨‍👩‍👦‍👦/IMG_1762.HEIC + 844 2024-05-25 22:15 Takeout/Google Photos/🇵🇹 Lisbonne ❤️ en famille 👨‍👩‍👦‍👦/PXL_20230813_052150006.jpg.json + 866 2024-05-25 22:15 Takeout/Google Photos/🇵🇹 Lisbonne ❤️ en famille 👨‍👩‍👦‍👦/PXL_20230813_045311490.jpg.json + 707 2024-05-25 22:15 Takeout/Google Photos/🇵🇹 Lisbonne ❤️ en famille 👨‍👩‍👦‍👦/IMG_1762.HEIC.json + 706 2024-05-25 22:15 Takeout/Google Photos/🇵🇹 Lisbonne ❤️ en famille 👨‍👩‍👦‍👦/IMG_1763.HEIC.json + 2734800 2024-05-25 22:15 Takeout/Google Photos/🇵🇹 Lisbonne ❤️ en famille 👨‍👩‍👦‍👦/IMG_1764.HEIC + 844 2024-05-25 22:15 Takeout/Google Photos/🇵🇹 Lisbonne ❤️ en famille 👨‍👩‍👦‍👦/PXL_20230813_053046647.jpg.json + 706 2024-05-25 22:15 Takeout/Google Photos/🇵🇹 Lisbonne ❤️ en famille 👨‍👩‍👦‍👦/IMG_1764.HEIC.json + 844 2024-05-25 22:15 Takeout/Google Photos/🇵🇹 Lisbonne ❤️ en famille 👨‍👩‍👦‍👦/PXL_20230813_053056618.jpg.json + 165685 2024-05-25 22:15 Takeout/Google Photos/Guillaumes 2018/IMG_8416-modifié.JPG + 2797125 2024-05-25 22:15 Takeout/Google Photos/🇵🇹 Lisbonne ❤️ en famille 👨‍👩‍👦‍👦/PXL_20230813_045318279.jpg + 860 2024-05-25 22:15 Takeout/Google Photos/🇵🇹 Lisbonne ❤️ en famille 👨‍👩‍👦‍👦/PXL_20230813_053450706.jpg.json + 844 2024-05-25 22:15 Takeout/Google Photos/🇵🇹 Lisbonne ❤️ en famille 👨‍👩‍👦‍👦/PXL_20230813_053252586.jpg.json + 2246976 2024-05-25 22:15 Takeout/Google Photos/🇵🇹 Lisbonne ❤️ en famille 👨‍👩‍👦‍👦/PXL_20230813_052150006.jpg + 1829557 2024-05-25 22:15 Takeout/Google Photos/🇵🇹 Lisbonne ❤️ en famille 👨‍👩‍👦‍👦/PXL_20230813_053252586.jpg + 860 2024-05-25 22:15 Takeout/Google Photos/🇵🇹 Lisbonne ❤️ en famille 👨‍👩‍👦‍👦/PXL_20230813_053257151.jpg.json + 1819407 2024-05-25 22:15 Takeout/Google Photos/🇵🇹 Lisbonne ❤️ en famille 👨‍👩‍👦‍👦/PXL_20230813_053046647.jpg + 2629906 2024-05-25 22:15 Takeout/Google Photos/🇵🇹 Lisbonne ❤️ en famille 👨‍👩‍👦‍👦/PXL_20230813_045312704.jpg + 3161101 2024-05-25 22:15 Takeout/Google Photos/🇵🇹 Lisbonne ❤️ en famille 👨‍👩‍👦‍👦/PXL_20230813_045311490.jpg + 1811270 2024-05-25 22:15 Takeout/Google Photos/🇵🇹 Lisbonne ❤️ en famille 👨‍👩‍👦‍👦/PXL_20230813_053257151.jpg + 862 2024-05-25 22:15 Takeout/Google Photos/🇵🇹 Lisbonne ❤️ en famille 👨‍👩‍👦‍👦/PXL_20230813_054704630.jpg.json + 880 2024-05-25 22:15 Takeout/Google Photos/🇵🇹 Lisbonne ❤️ en famille 👨‍👩‍👦‍👦/PXL_20230813_054809080.jpg.json + 2238741 2024-05-25 22:15 Takeout/Google Photos/🇵🇹 Lisbonne ❤️ en famille 👨‍👩‍👦‍👦/PXL_20230813_053056618.jpg + 850 2024-05-25 22:15 Takeout/Google Photos/🇵🇹 Lisbonne ❤️ en famille 👨‍👩‍👦‍👦/PXL_20230813_060922712.jpg.json + 882 2024-05-25 22:15 Takeout/Google Photos/🇵🇹 Lisbonne ❤️ en famille 👨‍👩‍👦‍👦/PXL_20230813_061449612.jpg.json + 1706679 2024-05-25 22:15 Takeout/Google Photos/🇵🇹 Lisbonne ❤️ en famille 👨‍👩‍👦‍👦/PXL_20230813_054704630.jpg + 868 2024-05-25 22:15 Takeout/Google Photos/🇵🇹 Lisbonne ❤️ en famille 👨‍👩‍👦‍👦/PXL_20230813_061617240.jpg.json + 1099162 2024-05-25 22:15 Takeout/Google Photos/🇵🇹 Lisbonne ❤️ en famille 👨‍👩‍👦‍👦/PXL_20230813_061617240.jpg + 866 2024-05-25 22:15 Takeout/Google Photos/🇵🇹 Lisbonne ❤️ en famille 👨‍👩‍👦‍👦/PXL_20230813_065633104.jpg.json + 864 2024-05-25 22:15 Takeout/Google Photos/🇵🇹 Lisbonne ❤️ en famille 👨‍👩‍👦‍👦/PXL_20230813_065541326.jpg.json + 2018556 2024-05-25 22:15 Takeout/Google Photos/🇵🇹 Lisbonne ❤️ en famille 👨‍👩‍👦‍👦/PXL_20230813_053450706.jpg + 1758371 2024-05-25 22:15 Takeout/Google Photos/🇵🇹 Lisbonne ❤️ en famille 👨‍👩‍👦‍👦/PXL_20230813_060922712.jpg + 1506192 2024-05-25 22:15 Takeout/Google Photos/🇵🇹 Lisbonne ❤️ en famille 👨‍👩‍👦‍👦/PXL_20230813_054809080.jpg + 866 2024-05-25 22:15 Takeout/Google Photos/🇵🇹 Lisbonne ❤️ en famille 👨‍👩‍👦‍👦/PXL_20230813_065651473.jpg.json + 1605479 2024-05-25 22:15 Takeout/Google Photos/🇵🇹 Lisbonne ❤️ en famille 👨‍👩‍👦‍👦/PXL_20230813_061449612.jpg + 854 2024-05-25 22:15 Takeout/Google Photos/🇵🇹 Lisbonne ❤️ en famille 👨‍👩‍👦‍👦/PXL_20230813_065801190.LS.mp4.json + 864 2024-05-25 22:15 Takeout/Google Photos/🇵🇹 Lisbonne ❤️ en famille 👨‍👩‍👦‍👦/PXL_20230813_070314539.jpg.json + 864 2024-05-25 22:15 Takeout/Google Photos/🇵🇹 Lisbonne ❤️ en famille 👨‍👩‍👦‍👦/PXL_20230813_071125792.jpg.json + 2513620 2024-05-25 22:15 Takeout/Google Photos/🇵🇹 Lisbonne ❤️ en famille 👨‍👩‍👦‍👦/PXL_20230813_065633104.jpg + 2689434 2024-05-25 22:15 Takeout/Google Photos/🇵🇹 Lisbonne ❤️ en famille 👨‍👩‍👦‍👦/PXL_20230813_065541326.jpg + 848 2024-05-25 22:15 Takeout/Google Photos/🇵🇹 Lisbonne ❤️ en famille 👨‍👩‍👦‍👦/PXL_20230813_072708786.jpg.json + 1680663 2024-05-25 22:15 Takeout/Google Photos/🇵🇹 Lisbonne ❤️ en famille 👨‍👩‍👦‍👦/PXL_20230813_071125792.jpg + 706 2024-05-25 22:15 Takeout/Google Photos/🇵🇹 Lisbonne ❤️ en famille 👨‍👩‍👦‍👦/IMG_1772.MOV.json + 868 2024-05-25 22:15 Takeout/Google Photos/🇵🇹 Lisbonne ❤️ en famille 👨‍👩‍👦‍👦/PXL_20230813_070539132.jpg.json + 705 2024-05-25 22:15 Takeout/Google Photos/🇵🇹 Lisbonne ❤️ en famille 👨‍👩‍👦‍👦/IMG_1767.MOV.json + 1839801 2024-05-25 22:15 Takeout/Google Photos/🇵🇹 Lisbonne ❤️ en famille 👨‍👩‍👦‍👦/PXL_20230813_070539132.jpg + 830 2024-05-25 22:15 Takeout/Google Photos/🇵🇹 Lisbonne ❤️ en famille 👨‍👩‍👦‍👦/PXL_20230813_074101341.LS.mp4.json + 2364569 2024-05-25 22:15 Takeout/Google Photos/🇵🇹 Lisbonne ❤️ en famille 👨‍👩‍👦‍👦/PXL_20230813_065651473.jpg + 2174283 2024-05-25 22:15 Takeout/Google Photos/🇵🇹 Lisbonne ❤️ en famille 👨‍👩‍👦‍👦/PXL_20230813_070314539.jpg + 860 2024-05-25 22:15 Takeout/Google Photos/🇵🇹 Lisbonne ❤️ en famille 👨‍👩‍👦‍👦/PXL_20230813_074326135.jpg.json + 860 2024-05-25 22:15 Takeout/Google Photos/🇵🇹 Lisbonne ❤️ en famille 👨‍👩‍👦‍👦/PXL_20230813_074330974.jpg.json + 842 2024-05-25 22:15 Takeout/Google Photos/🇵🇹 Lisbonne ❤️ en famille 👨‍👩‍👦‍👦/PXL_20230813_075720250.jpg.json + 826044 2024-05-25 22:15 Takeout/Google Photos/🇵🇹 Lisbonne ❤️ en famille 👨‍👩‍👦‍👦/PXL_20230813_065801190.LS.mp4 + 844 2024-05-25 22:15 Takeout/Google Photos/🇵🇹 Lisbonne ❤️ en famille 👨‍👩‍👦‍👦/PXL_20230813_080614621.jpg.json + 842 2024-05-25 22:15 Takeout/Google Photos/🇵🇹 Lisbonne ❤️ en famille 👨‍👩‍👦‍👦/PXL_20230813_075722087.jpg.json + 1475614 2024-05-25 22:15 Takeout/Google Photos/🇵🇹 Lisbonne ❤️ en famille 👨‍👩‍👦‍👦/PXL_20230813_074330974.jpg + 1402475 2024-05-25 22:15 Takeout/Google Photos/🇵🇹 Lisbonne ❤️ en famille 👨‍👩‍👦‍👦/PXL_20230813_074326135.jpg + 846 2024-05-25 22:15 Takeout/Google Photos/🇵🇹 Lisbonne ❤️ en famille 👨‍👩‍👦‍👦/PXL_20230813_080729129.jpg.json + 862 2024-05-25 22:15 Takeout/Google Photos/🇵🇹 Lisbonne ❤️ en famille 👨‍👩‍👦‍👦/PXL_20230813_080832073.jpg.json + 844 2024-05-25 22:15 Takeout/Google Photos/🇵🇹 Lisbonne ❤️ en famille 👨‍👩‍👦‍👦/PXL_20230813_080615786.jpg.json + 846 2024-05-25 22:15 Takeout/Google Photos/🇵🇹 Lisbonne ❤️ en famille 👨‍👩‍👦‍👦/PXL_20230813_074318267.jpg.json + 2357148 2024-05-25 22:15 Takeout/Google Photos/🇵🇹 Lisbonne ❤️ en famille 👨‍👩‍👦‍👦/PXL_20230813_080614621.jpg + 2258518 2024-05-25 22:15 Takeout/Google Photos/🇵🇹 Lisbonne ❤️ en famille 👨‍👩‍👦‍👦/PXL_20230813_072708786.jpg + 844 2024-05-25 22:15 Takeout/Google Photos/🇵🇹 Lisbonne ❤️ en famille 👨‍👩‍👦‍👦/PXL_20230813_085230735.jpg.json + 1960901 2024-05-25 22:15 Takeout/Google Photos/🇵🇹 Lisbonne ❤️ en famille 👨‍👩‍👦‍👦/PXL_20230813_075722087.jpg + 2428606 2024-05-25 22:15 Takeout/Google Photos/🇵🇹 Lisbonne ❤️ en famille 👨‍👩‍👦‍👦/PXL_20230813_080832073.jpg + 2009846 2024-05-25 22:15 Takeout/Google Photos/🇵🇹 Lisbonne ❤️ en famille 👨‍👩‍👦‍👦/PXL_20230813_075720250.jpg + 1067912 2024-05-25 22:15 Takeout/Google Photos/🇵🇹 Lisbonne ❤️ en famille 👨‍👩‍👦‍👦/PXL_20230813_074318267.jpg + 858 2024-05-25 22:15 Takeout/Google Photos/🇵🇹 Lisbonne ❤️ en famille 👨‍👩‍👦‍👦/PXL_20230813_085317917.jpg.json + 866 2024-05-25 22:15 Takeout/Google Photos/🇵🇹 Lisbonne ❤️ en famille 👨‍👩‍👦‍👦/PXL_20230813_065344256.jpg.json + 844 2024-05-25 22:15 Takeout/Google Photos/🇵🇹 Lisbonne ❤️ en famille 👨‍👩‍👦‍👦/PXL_20230813_085545918.jpg.json + 866 2024-05-25 22:15 Takeout/Google Photos/🇵🇹 Lisbonne ❤️ en famille 👨‍👩‍👦‍👦/PXL_20230813_065426987.jpg.json + 2877589 2024-05-25 22:15 Takeout/Google Photos/🇵🇹 Lisbonne ❤️ en famille 👨‍👩‍👦‍👦/PXL_20230813_080729129.jpg + 20458330 2024-05-25 22:15 Takeout/Google Photos/🇵🇹 Lisbonne ❤️ en famille 👨‍👩‍👦‍👦/IMG_1772.MOV + 2764415 2024-05-25 22:15 Takeout/Google Photos/🇵🇹 Lisbonne ❤️ en famille 👨‍👩‍👦‍👦/PXL_20230813_085230735.jpg + 844 2024-05-25 22:15 Takeout/Google Photos/🇵🇹 Lisbonne ❤️ en famille 👨‍👩‍👦‍👦/PXL_20230813_085707338.jpg.json + 2754160 2024-05-25 22:15 Takeout/Google Photos/🇵🇹 Lisbonne ❤️ en famille 👨‍👩‍👦‍👦/PXL_20230813_080615786.jpg + 43921624 2024-05-25 22:15 Takeout/Google Photos/🇵🇹 Lisbonne ❤️ en famille 👨‍👩‍👦‍👦/IMG_1767.MOV + 1664294 2024-05-25 22:15 Takeout/Google Photos/🇵🇹 Lisbonne ❤️ en famille 👨‍👩‍👦‍👦/PXL_20230813_065344256.jpg + 837 2024-05-25 22:15 Takeout/Google Photos/🇵🇹 Lisbonne ❤️ en famille 👨‍👩‍👦‍👦/PXL_20230813_093742072.PANO.jpg.json + 844 2024-05-25 22:15 Takeout/Google Photos/🇵🇹 Lisbonne ❤️ en famille 👨‍👩‍👦‍👦/PXL_20230813_085824598.jpg.json + 1947640 2024-05-25 22:15 Takeout/Google Photos/🇵🇹 Lisbonne ❤️ en famille 👨‍👩‍👦‍👦/PXL_20230813_065426987.jpg + 837 2024-05-25 22:15 Takeout/Google Photos/🇵🇹 Lisbonne ❤️ en famille 👨‍👩‍👦‍👦/PXL_20230813_095051535.PANO.jpg.json + 860 2024-05-25 22:15 Takeout/Google Photos/🇵🇹 Lisbonne ❤️ en famille 👨‍👩‍👦‍👦/PXL_20230813_094133465.jpg.json + 834 2024-05-25 22:15 Takeout/Google Photos/🇵🇹 Lisbonne ❤️ en famille 👨‍👩‍👦‍👦/PXL_20230813_095014093.jpg.json + 2951881 2024-05-25 22:15 Takeout/Google Photos/🇵🇹 Lisbonne ❤️ en famille 👨‍👩‍👦‍👦/PXL_20230813_085220659.jpg + 2928838 2024-05-25 22:15 Takeout/Google Photos/🇵🇹 Lisbonne ❤️ en famille 👨‍👩‍👦‍👦/PXL_20230813_093742072.PANO.jpg + 3054790 2024-05-25 22:15 Takeout/Google Photos/🇵🇹 Lisbonne ❤️ en famille 👨‍👩‍👦‍👦/PXL_20230813_085317917.jpg + 858 2024-05-25 22:15 Takeout/Google Photos/🇵🇹 Lisbonne ❤️ en famille 👨‍👩‍👦‍👦/PXL_20230813_100426120.jpg.json + 860 2024-05-25 22:15 Takeout/Google Photos/🇵🇹 Lisbonne ❤️ en famille 👨‍👩‍👦‍👦/PXL_20230813_095241390.jpg.json + 874 2024-05-25 22:15 Takeout/Google Photos/🇵🇹 Lisbonne ❤️ en famille 👨‍👩‍👦‍👦/PXL_20230813_101130729.jpg.json + 842 2024-05-25 22:15 Takeout/Google Photos/🇵🇹 Lisbonne ❤️ en famille 👨‍👩‍👦‍👦/PXL_20230813_101025932.jpg.json + 3249369 2024-05-25 22:15 Takeout/Google Photos/🇵🇹 Lisbonne ❤️ en famille 👨‍👩‍👦‍👦/PXL_20230813_095051535.PANO.jpg + 853 2024-05-25 22:15 Takeout/Google Photos/🇵🇹 Lisbonne ❤️ en famille 👨‍👩‍👦‍👦/PXL_20230813_104957115.LS.mp4.json + 3079050 2024-05-25 22:15 Takeout/Google Photos/🇵🇹 Lisbonne ❤️ en famille 👨‍👩‍👦‍👦/IMG_1773.HEIC + 3136587 2024-05-25 22:15 Takeout/Google Photos/🇵🇹 Lisbonne ❤️ en famille 👨‍👩‍👦‍👦/PXL_20230813_085545918.jpg + 862 2024-05-25 22:15 Takeout/Google Photos/🇵🇹 Lisbonne ❤️ en famille 👨‍👩‍👦‍👦/PXL_20230813_114039025.jpg.json + 3100522 2024-05-25 22:15 Takeout/Google Photos/🇵🇹 Lisbonne ❤️ en famille 👨‍👩‍👦‍👦/PXL_20230813_085707338.jpg + 1396573 2024-05-25 22:15 Takeout/Google Photos/🇵🇹 Lisbonne ❤️ en famille 👨‍👩‍👦‍👦/IMG_1775.HEIC + 858 2024-05-25 22:15 Takeout/Google Photos/🇵🇹 Lisbonne ❤️ en famille 👨‍👩‍👦‍👦/PXL_20230813_143108095.jpg.json + 3434665 2024-05-25 22:15 Takeout/Google Photos/🇵🇹 Lisbonne ❤️ en famille 👨‍👩‍👦‍👦/PXL_20230813_085824598.jpg + 2852147 2024-05-25 22:15 Takeout/Google Photos/🇵🇹 Lisbonne ❤️ en famille 👨‍👩‍👦‍👦/PXL_20230813_094133465.jpg + 2030183 2024-05-25 22:15 Takeout/Google Photos/🇵🇹 Lisbonne ❤️ en famille 👨‍👩‍👦‍👦/IMG_1776.HEIC + 2442085 2024-05-25 22:15 Takeout/Google Photos/🇵🇹 Lisbonne ❤️ en famille 👨‍👩‍👦‍👦/IMG_1774.HEIC + 1245550 2024-05-25 22:15 Takeout/Google Photos/🇵🇹 Lisbonne ❤️ en famille 👨‍👩‍👦‍👦/PXL_20230813_100426120.jpg + 2682608 2024-05-25 22:15 Takeout/Google Photos/🇵🇹 Lisbonne ❤️ en famille 👨‍👩‍👦‍👦/IMG_1778.HEIC + 1905682 2024-05-25 22:15 Takeout/Google Photos/🇵🇹 Lisbonne ❤️ en famille 👨‍👩‍👦‍👦/IMG_1780.HEIC + 706 2024-05-25 22:15 Takeout/Google Photos/🇵🇹 Lisbonne ❤️ en famille 👨‍👩‍👦‍👦/IMG_1774.HEIC.json + 1183599 2024-05-25 22:15 Takeout/Google Photos/🇵🇹 Lisbonne ❤️ en famille 👨‍👩‍👦‍👦/IMG_1782.HEIC + 706 2024-05-25 22:15 Takeout/Google Photos/🇵🇹 Lisbonne ❤️ en famille 👨‍👩‍👦‍👦/IMG_1775.HEIC.json + 706 2024-05-25 22:15 Takeout/Google Photos/🇵🇹 Lisbonne ❤️ en famille 👨‍👩‍👦‍👦/IMG_1776.HEIC.json + 1768315 2024-05-25 22:15 Takeout/Google Photos/🇵🇹 Lisbonne ❤️ en famille 👨‍👩‍👦‍👦/IMG_1777.HEIC + 3461019 2024-05-25 22:15 Takeout/Google Photos/🇵🇹 Lisbonne ❤️ en famille 👨‍👩‍👦‍👦/PXL_20230813_095241390.jpg + 1546245 2024-05-25 22:15 Takeout/Google Photos/🇵🇹 Lisbonne ❤️ en famille 👨‍👩‍👦‍👦/PXL_20230813_074101341.LS.mp4 + 2596682 2024-05-25 22:15 Takeout/Google Photos/🇵🇹 Lisbonne ❤️ en famille 👨‍👩‍👦‍👦/PXL_20230813_143108095.jpg + 706 2024-05-25 22:15 Takeout/Google Photos/🇵🇹 Lisbonne ❤️ en famille 👨‍👩‍👦‍👦/IMG_1779.HEIC.json + 706 2024-05-25 22:15 Takeout/Google Photos/🇵🇹 Lisbonne ❤️ en famille 👨‍👩‍👦‍👦/IMG_1780.HEIC.json + 2577241 2024-05-25 22:15 Takeout/Google Photos/🇵🇹 Lisbonne ❤️ en famille 👨‍👩‍👦‍👦/IMG_1779.HEIC + 3180012 2024-05-25 22:15 Takeout/Google Photos/🇵🇹 Lisbonne ❤️ en famille 👨‍👩‍👦‍👦/PXL_20230813_101130729.jpg + 706 2024-05-25 22:15 Takeout/Google Photos/🇵🇹 Lisbonne ❤️ en famille 👨‍👩‍👦‍👦/IMG_1778.HEIC.json + 699580 2024-05-25 22:15 Takeout/Google Photos/🇵🇹 Lisbonne ❤️ en famille 👨‍👩‍👦‍👦/IMG_1787.HEIC + 4030321 2024-05-25 22:15 Takeout/Google Photos/🇵🇹 Lisbonne ❤️ en famille 👨‍👩‍👦‍👦/PXL_20230813_095014093.jpg + 3402509 2024-05-25 22:15 Takeout/Google Photos/🇵🇹 Lisbonne ❤️ en famille 👨‍👩‍👦‍👦/IMG_1781.HEIC + 2281196 2024-05-25 22:15 Takeout/Google Photos/🇵🇹 Lisbonne ❤️ en famille 👨‍👩‍👦‍👦/IMG_1786.HEIC + 706 2024-05-25 22:15 Takeout/Google Photos/🇵🇹 Lisbonne ❤️ en famille 👨‍👩‍👦‍👦/IMG_1777.HEIC.json + 706 2024-05-25 22:15 Takeout/Google Photos/🇵🇹 Lisbonne ❤️ en famille 👨‍👩‍👦‍👦/IMG_1783.HEIC.json + 3181783 2024-05-25 22:15 Takeout/Google Photos/🇵🇹 Lisbonne ❤️ en famille 👨‍👩‍👦‍👦/IMG_1783.HEIC + 706 2024-05-25 22:15 Takeout/Google Photos/🇵🇹 Lisbonne ❤️ en famille 👨‍👩‍👦‍👦/IMG_1784.HEIC.json + 706 2024-05-25 22:15 Takeout/Google Photos/🇵🇹 Lisbonne ❤️ en famille 👨‍👩‍👦‍👦/IMG_1781.HEIC.json + 2332185 2024-05-25 22:15 Takeout/Google Photos/🇵🇹 Lisbonne ❤️ en famille 👨‍👩‍👦‍👦/IMG_1791.HEIC + 2296877 2024-05-25 22:15 Takeout/Google Photos/🇵🇹 Lisbonne ❤️ en famille 👨‍👩‍👦‍👦/IMG_1785.HEIC + 706 2024-05-25 22:15 Takeout/Google Photos/🇵🇹 Lisbonne ❤️ en famille 👨‍👩‍👦‍👦/IMG_1782.HEIC.json + 3649659 2024-05-25 22:15 Takeout/Google Photos/🇵🇹 Lisbonne ❤️ en famille 👨‍👩‍👦‍👦/IMG_1784.HEIC + 706 2024-05-25 22:15 Takeout/Google Photos/🇵🇹 Lisbonne ❤️ en famille 👨‍👩‍👦‍👦/IMG_1785.HEIC.json + 706 2024-05-25 22:15 Takeout/Google Photos/🇵🇹 Lisbonne ❤️ en famille 👨‍👩‍👦‍👦/IMG_1786.HEIC.json + 706 2024-05-25 22:15 Takeout/Google Photos/🇵🇹 Lisbonne ❤️ en famille 👨‍👩‍👦‍👦/IMG_1791.HEIC.json + 3173006 2024-05-25 22:15 Takeout/Google Photos/🇵🇹 Lisbonne ❤️ en famille 👨‍👩‍👦‍👦/PXL_20230813_101025932.jpg + 706 2024-05-25 22:15 Takeout/Google Photos/🇵🇹 Lisbonne ❤️ en famille 👨‍👩‍👦‍👦/IMG_1788.HEIC.json + 706 2024-05-25 22:15 Takeout/Google Photos/🇵🇹 Lisbonne ❤️ en famille 👨‍👩‍👦‍👦/IMG_1787.HEIC.json + 2778043 2024-05-25 22:15 Takeout/Google Photos/🇵🇹 Lisbonne ❤️ en famille 👨‍👩‍👦‍👦/IMG_1788.HEIC + 846 2024-05-25 22:15 Takeout/Google Photos/🇵🇹 Lisbonne ❤️ en famille 👨‍👩‍👦‍👦/PXL_20230813_175934570.jpg.json + 844 2024-05-25 22:15 Takeout/Google Photos/🇵🇹 Lisbonne ❤️ en famille 👨‍👩‍👦‍👦/PXL_20230813_173903662.jpg.json + 842 2024-05-25 22:15 Takeout/Google Photos/🇵🇹 Lisbonne ❤️ en famille 👨‍👩‍👦‍👦/PXL_20230813_172315843.jpg.json + 5621814 2024-05-25 22:15 Takeout/Google Photos/🇵🇹 Lisbonne ❤️ en famille 👨‍👩‍👦‍👦/PXL_20230813_114039025.jpg + 846 2024-05-25 22:15 Takeout/Google Photos/🇵🇹 Lisbonne ❤️ en famille 👨‍👩‍👦‍👦/PXL_20230813_175940633.jpg.json + 27203585 2024-05-25 22:15 Takeout/Google Photos/Guillaumes 2018/Bebop2_20180723180057+0200.m4v + 846 2024-05-25 22:15 Takeout/Google Photos/🇵🇹 Lisbonne ❤️ en famille 👨‍👩‍👦‍👦/PXL_20230813_172540663.jpg.json + 862 2024-05-25 22:15 Takeout/Google Photos/🇵🇹 Lisbonne ❤️ en famille 👨‍👩‍👦‍👦/PXL_20230813_181336232.jpg.json + 862 2024-05-25 22:15 Takeout/Google Photos/🇵🇹 Lisbonne ❤️ en famille 👨‍👩‍👦‍👦/PXL_20230813_181337872.jpg.json + 860 2024-05-25 22:15 Takeout/Google Photos/🇵🇹 Lisbonne ❤️ en famille 👨‍👩‍👦‍👦/PXL_20230813_180819064.jpg.json + 846 2024-05-25 22:15 Takeout/Google Photos/🇵🇹 Lisbonne ❤️ en famille 👨‍👩‍👦‍👦/PXL_20230813_180515752.jpg.json + 2894559 2024-05-25 22:15 Takeout/Google Photos/🇵🇹 Lisbonne ❤️ en famille 👨‍👩‍👦‍👦/PXL_20230813_173903662.jpg + 1875846 2024-05-25 22:15 Takeout/Google Photos/🇵🇹 Lisbonne ❤️ en famille 👨‍👩‍👦‍👦/PXL_20230813_180819064.jpg + 4769063 2024-05-25 22:15 Takeout/Google Photos/🇵🇹 Lisbonne ❤️ en famille 👨‍👩‍👦‍👦/PXL_20230813_104957115.LS.mp4 + 846 2024-05-25 22:15 Takeout/Google Photos/🇵🇹 Lisbonne ❤️ en famille 👨‍👩‍👦‍👦/PXL_20230813_181918957.jpg.json + 852 2024-05-25 22:15 Takeout/Google Photos/🇵🇹 Lisbonne ❤️ en famille 👨‍👩‍👦‍👦/PXL_20230813_202853503.NIGHT.jpg.json + 852 2024-05-25 22:15 Takeout/Google Photos/🇵🇹 Lisbonne ❤️ en famille 👨‍👩‍👦‍👦/PXL_20230813_202938567.NIGHT.jpg.json + 3611141 2024-05-25 22:15 Takeout/Google Photos/🇵🇹 Lisbonne ❤️ en famille 👨‍👩‍👦‍👦/PXL_20230813_172315843.jpg + 846 2024-05-25 22:15 Takeout/Google Photos/🇵🇹 Lisbonne ❤️ en famille 👨‍👩‍👦‍👦/PXL_20230813_181952207.jpg.json + 953011 2024-05-25 22:15 Takeout/Google Photos/🇵🇹 Lisbonne ❤️ en famille 👨‍👩‍👦‍👦/IMG_1795.HEIC + 2005029 2024-05-25 22:15 Takeout/Google Photos/🇵🇹 Lisbonne ❤️ en famille 👨‍👩‍👦‍👦/IMG_1794.HEIC + 3031838 2024-05-25 22:15 Takeout/Google Photos/🇵🇹 Lisbonne ❤️ en famille 👨‍👩‍👦‍👦/PXL_20230813_180515752.jpg + 2052762 2024-05-25 22:15 Takeout/Google Photos/🇵🇹 Lisbonne ❤️ en famille 👨‍👩‍👦‍👦/PXL_20230813_181336232.jpg + 2239188 2024-05-25 22:15 Takeout/Google Photos/🇵🇹 Lisbonne ❤️ en famille 👨‍👩‍👦‍👦/PXL_20230813_181337872.jpg + 862 2024-05-25 22:15 Takeout/Google Photos/🇵🇹 Lisbonne ❤️ en famille 👨‍👩‍👦‍👦/PXL_20230813_203007881.jpg.json + 868 2024-05-25 22:15 Takeout/Google Photos/🇵🇹 Lisbonne ❤️ en famille 👨‍👩‍👦‍👦/PXL_20230813_203016989.NIGHT.jpg.json + 848 2024-05-25 22:15 Takeout/Google Photos/🇵🇹 Lisbonne ❤️ en famille 👨‍👩‍👦‍👦/PXL_20230813_203051232.NIGHT.jpg.json + 862 2024-05-25 22:15 Takeout/Google Photos/🇵🇹 Lisbonne ❤️ en famille 👨‍👩‍👦‍👦/PXL_20230813_203004692.jpg.json + 2249199 2024-05-25 22:15 Takeout/Google Photos/🇵🇹 Lisbonne ❤️ en famille 👨‍👩‍👦‍👦/PXL_20230813_175940633.jpg + 2971596 2024-05-25 22:15 Takeout/Google Photos/🇵🇹 Lisbonne ❤️ en famille 👨‍👩‍👦‍👦/PXL_20230813_181952207.jpg + 2149199 2024-05-25 22:15 Takeout/Google Photos/🇵🇹 Lisbonne ❤️ en famille 👨‍👩‍👦‍👦/PXL_20230813_175934570.jpg + 1988569 2024-05-25 22:15 Takeout/Google Photos/🇵🇹 Lisbonne ❤️ en famille 👨‍👩‍👦‍👦/IMG_1796.HEIC + 4191014 2024-05-25 22:15 Takeout/Google Photos/🇵🇹 Lisbonne ❤️ en famille 👨‍👩‍👦‍👦/PXL_20230813_172540663.jpg + 1785180 2024-05-25 22:15 Takeout/Google Photos/🇵🇹 Lisbonne ❤️ en famille 👨‍👩‍👦‍👦/IMG_1798.HEIC + 1685183 2024-05-25 22:15 Takeout/Google Photos/🇵🇹 Lisbonne ❤️ en famille 👨‍👩‍👦‍👦/PXL_20230813_203004692.jpg + 3673018 2024-05-25 22:15 Takeout/Google Photos/🇵🇹 Lisbonne ❤️ en famille 👨‍👩‍👦‍👦/PXL_20230813_181918957.jpg + 706 2024-05-25 22:15 Takeout/Google Photos/🇵🇹 Lisbonne ❤️ en famille 👨‍👩‍👦‍👦/IMG_1795.HEIC.json + 2372396 2024-05-25 22:15 Takeout/Google Photos/🇵🇹 Lisbonne ❤️ en famille 👨‍👩‍👦‍👦/PXL_20230813_202853503.NIGHT.jpg + 706 2024-05-25 22:15 Takeout/Google Photos/🇵🇹 Lisbonne ❤️ en famille 👨‍👩‍👦‍👦/IMG_1794.HEIC.json + 1688525 2024-05-25 22:15 Takeout/Google Photos/🇵🇹 Lisbonne ❤️ en famille 👨‍👩‍👦‍👦/PXL_20230813_203007881.jpg + 1474426 2024-05-25 22:15 Takeout/Google Photos/🇵🇹 Lisbonne ❤️ en famille 👨‍👩‍👦‍👦/PXL_20230813_203051232.NIGHT.jpg + 860 2024-05-25 22:15 Takeout/Google Photos/🇵🇹 Lisbonne ❤️ en famille 👨‍👩‍👦‍👦/PXL_20230814_071217029.jpg.json + 954052 2024-05-25 22:15 Takeout/Google Photos/🇵🇹 Lisbonne ❤️ en famille 👨‍👩‍👦‍👦/IMG_1803.HEIC + 1357647 2024-05-25 22:15 Takeout/Google Photos/🇵🇹 Lisbonne ❤️ en famille 👨‍👩‍👦‍👦/IMG_1802.HEIC + 2217158 2024-05-25 22:15 Takeout/Google Photos/🇵🇹 Lisbonne ❤️ en famille 👨‍👩‍👦‍👦/IMG_1801.HEIC + 2045173 2024-05-25 22:15 Takeout/Google Photos/🇵🇹 Lisbonne ❤️ en famille 👨‍👩‍👦‍👦/IMG_1797.HEIC + 706 2024-05-25 22:15 Takeout/Google Photos/🇵🇹 Lisbonne ❤️ en famille 👨‍👩‍👦‍👦/IMG_1796.HEIC.json + 706 2024-05-25 22:15 Takeout/Google Photos/🇵🇹 Lisbonne ❤️ en famille 👨‍👩‍👦‍👦/IMG_1798.HEIC.json + 2291074 2024-05-25 22:15 Takeout/Google Photos/🇵🇹 Lisbonne ❤️ en famille 👨‍👩‍👦‍👦/IMG_1799.HEIC + 706 2024-05-25 22:15 Takeout/Google Photos/🇵🇹 Lisbonne ❤️ en famille 👨‍👩‍👦‍👦/IMG_1797.HEIC.json + 2518704 2024-05-25 22:15 Takeout/Google Photos/🇵🇹 Lisbonne ❤️ en famille 👨‍👩‍👦‍👦/PXL_20230813_202938567.NIGHT.jpg + 706 2024-05-25 22:15 Takeout/Google Photos/🇵🇹 Lisbonne ❤️ en famille 👨‍👩‍👦‍👦/IMG_1799.HEIC.json + 1752476 2024-05-25 22:15 Takeout/Google Photos/🇵🇹 Lisbonne ❤️ en famille 👨‍👩‍👦‍👦/PXL_20230813_203016989.NIGHT.jpg + 706 2024-05-25 22:15 Takeout/Google Photos/🇵🇹 Lisbonne ❤️ en famille 👨‍👩‍👦‍👦/IMG_1800.HEIC.json + 2350286 2024-05-25 22:15 Takeout/Google Photos/🇵🇹 Lisbonne ❤️ en famille 👨‍👩‍👦‍👦/IMG_1800.HEIC + 706 2024-05-25 22:15 Takeout/Google Photos/🇵🇹 Lisbonne ❤️ en famille 👨‍👩‍👦‍👦/IMG_1801.HEIC.json + 706 2024-05-25 22:15 Takeout/Google Photos/🇵🇹 Lisbonne ❤️ en famille 👨‍👩‍👦‍👦/IMG_1802.HEIC.json + 706 2024-05-25 22:15 Takeout/Google Photos/🇵🇹 Lisbonne ❤️ en famille 👨‍👩‍👦‍👦/IMG_1803.HEIC.json + 840 2024-05-25 22:15 Takeout/Google Photos/🇵🇹 Lisbonne ❤️ en famille 👨‍👩‍👦‍👦/PXL_20230814_083758386.jpg.json + 2750364 2024-05-25 22:15 Takeout/Google Photos/🇵🇹 Lisbonne ❤️ en famille 👨‍👩‍👦‍👦/PXL_20230814_071217029.jpg + 878 2024-05-25 22:15 Takeout/Google Photos/🇵🇹 Lisbonne ❤️ en famille 👨‍👩‍👦‍👦/PXL_20230814_085041151.jpg.json + 853 2024-05-25 22:15 Takeout/Google Photos/🇵🇹 Lisbonne ❤️ en famille 👨‍👩‍👦‍👦/PXL_20230814_085134035.LS.mp4.json + 848 2024-05-25 22:15 Takeout/Google Photos/🇵🇹 Lisbonne ❤️ en famille 👨‍👩‍👦‍👦/PXL_20230814_085348060.mp4.json + 828 2024-05-25 22:15 Takeout/Google Photos/🇵🇹 Lisbonne ❤️ en famille 👨‍👩‍👦‍👦/PXL_20230814_085241731.mp4.json + 828 2024-05-25 22:15 Takeout/Google Photos/🇵🇹 Lisbonne ❤️ en famille 👨‍👩‍👦‍👦/PXL_20230814_090912639.mp4.json + 853 2024-05-25 22:15 Takeout/Google Photos/🇵🇹 Lisbonne ❤️ en famille 👨‍👩‍👦‍👦/PXL_20230814_085142027.TS.mp4.json + 848 2024-05-25 22:15 Takeout/Google Photos/🇵🇹 Lisbonne ❤️ en famille 👨‍👩‍👦‍👦/PXL_20230814_085641282.mp4.json + 846 2024-05-25 22:15 Takeout/Google Photos/🇵🇹 Lisbonne ❤️ en famille 👨‍👩‍👦‍👦/PXL_20230814_091023980.jpg.json + 848 2024-05-25 22:15 Takeout/Google Photos/🇵🇹 Lisbonne ❤️ en famille 👨‍👩‍👦‍👦/PXL_20230814_085417927.mp4.json + 846 2024-05-25 22:15 Takeout/Google Photos/🇵🇹 Lisbonne ❤️ en famille 👨‍👩‍👦‍👦/PXL_20230814_091029409.jpg.json + 846 2024-05-25 22:15 Takeout/Google Photos/🇵🇹 Lisbonne ❤️ en famille 👨‍👩‍👦‍👦/PXL_20230814_091031920.jpg.json + 846 2024-05-25 22:15 Takeout/Google Photos/🇵🇹 Lisbonne ❤️ en famille 👨‍👩‍👦‍👦/PXL_20230814_091035587.jpg.json + 862 2024-05-25 22:15 Takeout/Google Photos/🇵🇹 Lisbonne ❤️ en famille 👨‍👩‍👦‍👦/PXL_20230814_091328950.jpg.json + 862 2024-05-25 22:15 Takeout/Google Photos/🇵🇹 Lisbonne ❤️ en famille 👨‍👩‍👦‍👦/PXL_20230814_091609310.jpg.json + 862 2024-05-25 22:15 Takeout/Google Photos/🇵🇹 Lisbonne ❤️ en famille 👨‍👩‍👦‍👦/PXL_20230814_091608239.jpg.json + 154044 2024-05-25 22:15 Takeout/Google Photos/🇵🇹 Lisbonne ❤️ en famille 👨‍👩‍👦‍👦/PXL_20230814_085417927.mp4 + 860 2024-05-25 22:15 Takeout/Google Photos/🇵🇹 Lisbonne ❤️ en famille 👨‍👩‍👦‍👦/PXL_20230814_091959433.jpg.json + 860 2024-05-25 22:15 Takeout/Google Photos/🇵🇹 Lisbonne ❤️ en famille 👨‍👩‍👦‍👦/PXL_20230814_092000946.jpg.json + 860 2024-05-25 22:15 Takeout/Google Photos/🇵🇹 Lisbonne ❤️ en famille 👨‍👩‍👦‍👦/PXL_20230814_092304596.jpg.json + 2473525 2024-05-25 22:15 Takeout/Google Photos/🇵🇹 Lisbonne ❤️ en famille 👨‍👩‍👦‍👦/PXL_20230814_091959433.jpg + 4594317 2024-05-25 22:15 Takeout/Google Photos/🇵🇹 Lisbonne ❤️ en famille 👨‍👩‍👦‍👦/PXL_20230814_085041151.jpg + 1894384 2024-05-25 22:15 Takeout/Google Photos/🇵🇹 Lisbonne ❤️ en famille 👨‍👩‍👦‍👦/PXL_20230814_092000946.jpg + 860 2024-05-25 22:15 Takeout/Google Photos/🇵🇹 Lisbonne ❤️ en famille 👨‍👩‍👦‍👦/PXL_20230814_092309141.jpg.json + 850572 2024-05-25 22:15 Takeout/Google Photos/🇵🇹 Lisbonne ❤️ en famille 👨‍👩‍👦‍👦/IMG_1804.HEIC + 828 2024-05-25 22:15 Takeout/Google Photos/🇵🇹 Lisbonne ❤️ en famille 👨‍👩‍👦‍👦/PXL_20230814_093331250.mp4.json + 2356936 2024-05-25 22:15 Takeout/Google Photos/🇵🇹 Lisbonne ❤️ en famille 👨‍👩‍👦‍👦/PXL_20230814_091031920.jpg + 514406 2024-05-25 22:15 Takeout/Google Photos/🇵🇹 Lisbonne ❤️ en famille 👨‍👩‍👦‍👦/PXL_20230814_085641282.mp4 + 3200270 2024-05-25 22:15 Takeout/Google Photos/🇵🇹 Lisbonne ❤️ en famille 👨‍👩‍👦‍👦/PXL_20230814_085134035.LS.mp4 + 3232353 2024-05-25 22:15 Takeout/Google Photos/🇵🇹 Lisbonne ❤️ en famille 👨‍👩‍👦‍👦/PXL_20230814_091035587.jpg + 4151500 2024-05-25 22:15 Takeout/Google Photos/🇵🇹 Lisbonne ❤️ en famille 👨‍👩‍👦‍👦/PXL_20230814_083758386.jpg + 850 2024-05-25 22:15 Takeout/Google Photos/🇵🇹 Lisbonne ❤️ en famille 👨‍👩‍👦‍👦/PXL_20230814_093746681.mp4.json + 3846315 2024-05-25 22:15 Takeout/Google Photos/🇵🇹 Lisbonne ❤️ en famille 👨‍👩‍👦‍👦/PXL_20230814_091608239.jpg + 3839435 2024-05-25 22:15 Takeout/Google Photos/🇵🇹 Lisbonne ❤️ en famille 👨‍👩‍👦‍👦/PXL_20230814_091609310.jpg + 706 2024-05-25 22:15 Takeout/Google Photos/🇵🇹 Lisbonne ❤️ en famille 👨‍👩‍👦‍👦/IMG_1804.HEIC.json + 2439866 2024-05-25 22:15 Takeout/Google Photos/🇵🇹 Lisbonne ❤️ en famille 👨‍👩‍👦‍👦/PXL_20230814_091029409.jpg + 880 2024-05-25 22:15 Takeout/Google Photos/🇵🇹 Lisbonne ❤️ en famille 👨‍👩‍👦‍👦/PXL_20230814_094846004.PORTRAIT.ORIGINAL.jpg.json + 862 2024-05-25 22:15 Takeout/Google Photos/🇵🇹 Lisbonne ❤️ en famille 👨‍👩‍👦‍👦/PXL_20230814_094907387.jpg.json + 4431123 2024-05-25 22:15 Takeout/Google Photos/🇵🇹 Lisbonne ❤️ en famille 👨‍👩‍👦‍👦/PXL_20230814_091328950.jpg + 4982318 2024-05-25 22:15 Takeout/Google Photos/🇵🇹 Lisbonne ❤️ en famille 👨‍👩‍👦‍👦/PXL_20230814_091023980.jpg + 862 2024-05-25 22:15 Takeout/Google Photos/🇵🇹 Lisbonne ❤️ en famille 👨‍👩‍👦‍👦/PXL_20230814_095433860.jpg.json + 838 2024-05-25 22:15 Takeout/Google Photos/🇵🇹 Lisbonne ❤️ en famille 👨‍👩‍👦‍👦/PXL_20230814_100609571.jpg.json + 8171047 2024-05-25 22:15 Takeout/Google Photos/🇵🇹 Lisbonne ❤️ en famille 👨‍👩‍👦‍👦/PXL_20230814_090912639.mp4 + 1751462 2024-05-25 22:15 Takeout/Google Photos/🇵🇹 Lisbonne ❤️ en famille 👨‍👩‍👦‍👦/PXL_20230814_095433860.jpg + 860 2024-05-25 22:15 Takeout/Google Photos/🇵🇹 Lisbonne ❤️ en famille 👨‍👩‍👦‍👦/PXL_20230814_100754362.jpg.json + 846 2024-05-25 22:15 Takeout/Google Photos/🇵🇹 Lisbonne ❤️ en famille 👨‍👩‍👦‍👦/PXL_20230814_100934441.jpg.json + 2590405 2024-05-25 22:15 Takeout/Google Photos/🇵🇹 Lisbonne ❤️ en famille 👨‍👩‍👦‍👦/PXL_20230814_094907387.jpg + 4204935 2024-05-25 22:15 Takeout/Google Photos/🇵🇹 Lisbonne ❤️ en famille 👨‍👩‍👦‍👦/PXL_20230814_092304596.jpg + 1913930 2024-05-25 22:15 Takeout/Google Photos/🇵🇹 Lisbonne ❤️ en famille 👨‍👩‍👦‍👦/PXL_20230814_094846004.PORTRAIT.ORIGINAL.jpg + 844 2024-05-25 22:15 Takeout/Google Photos/🇵🇹 Lisbonne ❤️ en famille 👨‍👩‍👦‍👦/PXL_20230814_101954705.jpg.json + 4938850 2024-05-25 22:15 Takeout/Google Photos/🇵🇹 Lisbonne ❤️ en famille 👨‍👩‍👦‍👦/PXL_20230814_085348060.mp4 + 844 2024-05-25 22:15 Takeout/Google Photos/🇵🇹 Lisbonne ❤️ en famille 👨‍👩‍👦‍👦/PXL_20230814_101958829.jpg.json + 844 2024-05-25 22:15 Takeout/Google Photos/🇵🇹 Lisbonne ❤️ en famille 👨‍👩‍👦‍👦/PXL_20230814_101956501.jpg.json + 842 2024-05-25 22:15 Takeout/Google Photos/🇵🇹 Lisbonne ❤️ en famille 👨‍👩‍👦‍👦/PXL_20230814_103647627.jpg.json + 860 2024-05-25 22:15 Takeout/Google Photos/🇵🇹 Lisbonne ❤️ en famille 👨‍👩‍👦‍👦/PXL_20230814_102604015.jpg.json + 2616162 2024-05-25 22:15 Takeout/Google Photos/🇵🇹 Lisbonne ❤️ en famille 👨‍👩‍👦‍👦/PXL_20230814_100754362.jpg + 858 2024-05-25 22:15 Takeout/Google Photos/🇵🇹 Lisbonne ❤️ en famille 👨‍👩‍👦‍👦/PXL_20230814_102135803.jpg.json + 1676634 2024-05-25 22:15 Takeout/Google Photos/🇵🇹 Lisbonne ❤️ en famille 👨‍👩‍👦‍👦/PXL_20230814_101956501.jpg + 2122990 2024-05-25 22:15 Takeout/Google Photos/🇵🇹 Lisbonne ❤️ en famille 👨‍👩‍👦‍👦/PXL_20230814_100934441.jpg + 1704142 2024-05-25 22:15 Takeout/Google Photos/🇵🇹 Lisbonne ❤️ en famille 👨‍👩‍👦‍👦/PXL_20230814_101954705.jpg + 842 2024-05-25 22:15 Takeout/Google Photos/🇵🇹 Lisbonne ❤️ en famille 👨‍👩‍👦‍👦/PXL_20230814_103652839.jpg.json + 838 2024-05-25 22:15 Takeout/Google Photos/🇵🇹 Lisbonne ❤️ en famille 👨‍👩‍👦‍👦/PXL_20230814_104311200.jpg.json + 4648621 2024-05-25 22:15 Takeout/Google Photos/🇵🇹 Lisbonne ❤️ en famille 👨‍👩‍👦‍👦/PXL_20230814_085241731.mp4 + 842 2024-05-25 22:15 Takeout/Google Photos/🇵🇹 Lisbonne ❤️ en famille 👨‍👩‍👦‍👦/PXL_20230814_103704197.jpg.json + 838 2024-05-25 22:15 Takeout/Google Photos/🇵🇹 Lisbonne ❤️ en famille 👨‍👩‍👦‍👦/PXL_20230814_104355371.jpg.json + 9350036 2024-05-25 22:15 Takeout/Google Photos/🇵🇹 Lisbonne ❤️ en famille 👨‍👩‍👦‍👦/PXL_20230814_093331250.mp4 + 1894488 2024-05-25 22:15 Takeout/Google Photos/🇵🇹 Lisbonne ❤️ en famille 👨‍👩‍👦‍👦/PXL_20230814_101958829.jpg + 3945359 2024-05-25 22:15 Takeout/Google Photos/🇵🇹 Lisbonne ❤️ en famille 👨‍👩‍👦‍👦/PXL_20230814_100609571.jpg + 844 2024-05-25 22:15 Takeout/Google Photos/🇵🇹 Lisbonne ❤️ en famille 👨‍👩‍👦‍👦/PXL_20230814_104439655.jpg.json + 2883623 2024-05-25 22:15 Takeout/Google Photos/🇵🇹 Lisbonne ❤️ en famille 👨‍👩‍👦‍👦/PXL_20230814_092309141.jpg + 844 2024-05-25 22:15 Takeout/Google Photos/🇵🇹 Lisbonne ❤️ en famille 👨‍👩‍👦‍👦/PXL_20230814_104535388.jpg.json + 2177026 2024-05-25 22:15 Takeout/Google Photos/🇵🇹 Lisbonne ❤️ en famille 👨‍👩‍👦‍👦/PXL_20230814_102604015.jpg + 842 2024-05-25 22:15 Takeout/Google Photos/🇵🇹 Lisbonne ❤️ en famille 👨‍👩‍👦‍👦/PXL_20230814_104550263.jpg.json + 4094755 2024-05-25 22:15 Takeout/Google Photos/🇵🇹 Lisbonne ❤️ en famille 👨‍👩‍👦‍👦/PXL_20230814_102135803.jpg + 842 2024-05-25 22:15 Takeout/Google Photos/🇵🇹 Lisbonne ❤️ en famille 👨‍👩‍👦‍👦/PXL_20230814_104646669.jpg.json + 3365027 2024-05-25 22:15 Takeout/Google Photos/🇵🇹 Lisbonne ❤️ en famille 👨‍👩‍👦‍👦/PXL_20230814_103652839.jpg + 844 2024-05-25 22:15 Takeout/Google Photos/🇵🇹 Lisbonne ❤️ en famille 👨‍👩‍👦‍👦/PXL_20230814_105115882.jpg.json + 844 2024-05-25 22:15 Takeout/Google Photos/🇵🇹 Lisbonne ❤️ en famille 👨‍👩‍👦‍👦/PXL_20230814_105118064.jpg.json + 2824711 2024-05-25 22:15 Takeout/Google Photos/🇵🇹 Lisbonne ❤️ en famille 👨‍👩‍👦‍👦/PXL_20230814_103647627.jpg + 874 2024-05-25 22:15 Takeout/Google Photos/🇵🇹 Lisbonne ❤️ en famille 👨‍👩‍👦‍👦/PXL_20230814_111430712.jpg.json + 2523883 2024-05-25 22:15 Takeout/Google Photos/🇵🇹 Lisbonne ❤️ en famille 👨‍👩‍👦‍👦/PXL_20230814_103704197.jpg + 858 2024-05-25 22:15 Takeout/Google Photos/🇵🇹 Lisbonne ❤️ en famille 👨‍👩‍👦‍👦/PXL_20230814_111310171.jpg.json + 845 2024-05-25 22:15 Takeout/Google Photos/🇵🇹 Lisbonne ❤️ en famille 👨‍👩‍👦‍👦/PXL_20230814_112118374.PANO.jpg.json + 2306670 2024-05-25 22:15 Takeout/Google Photos/🇵🇹 Lisbonne ❤️ en famille 👨‍👩‍👦‍👦/PXL_20230814_105118064.jpg + 1516138 2024-05-25 22:15 Takeout/Google Photos/🇵🇹 Lisbonne ❤️ en famille 👨‍👩‍👦‍👦/PXL_20230814_112118374.PANO.jpg + 872 2024-05-25 22:15 Takeout/Google Photos/🇵🇹 Lisbonne ❤️ en famille 👨‍👩‍👦‍👦/PXL_20230814_112941866.jpg.json + 3807836 2024-05-25 22:15 Takeout/Google Photos/🇵🇹 Lisbonne ❤️ en famille 👨‍👩‍👦‍👦/PXL_20230814_104550263.jpg + 872 2024-05-25 22:15 Takeout/Google Photos/🇵🇹 Lisbonne ❤️ en famille 👨‍👩‍👦‍👦/PXL_20230814_112926703.jpg.json + 323256 2024-05-25 22:15 Takeout/Google Photos/🇵🇹 Lisbonne ❤️ en famille 👨‍👩‍👦‍👦/PXL_20230814_093746681.mp4 + 872 2024-05-25 22:15 Takeout/Google Photos/🇵🇹 Lisbonne ❤️ en famille 👨‍👩‍👦‍👦/PXL_20230814_112944670.jpg.json + 1387263 2024-05-25 22:15 Takeout/Google Photos/🇵🇹 Lisbonne ❤️ en famille 👨‍👩‍👦‍👦/IMG_1805.HEIC + 2711896 2024-05-25 22:15 Takeout/Google Photos/🇵🇹 Lisbonne ❤️ en famille 👨‍👩‍👦‍👦/PXL_20230814_104355371.jpg + 844 2024-05-25 22:15 Takeout/Google Photos/🇵🇹 Lisbonne ❤️ en famille 👨‍👩‍👦‍👦/PXL_20230814_113132593.jpg.json + 2940811 2024-05-25 22:15 Takeout/Google Photos/🇵🇹 Lisbonne ❤️ en famille 👨‍👩‍👦‍👦/PXL_20230814_112926703.jpg + 876 2024-05-25 22:15 Takeout/Google Photos/🇵🇹 Lisbonne ❤️ en famille 👨‍👩‍👦‍👦/PXL_20230814_113936027.jpg.json + 876 2024-05-25 22:15 Takeout/Google Photos/🇵🇹 Lisbonne ❤️ en famille 👨‍👩‍👦‍👦/PXL_20230814_114626362.jpg.json + 3446024 2024-05-25 22:15 Takeout/Google Photos/🇵🇹 Lisbonne ❤️ en famille 👨‍👩‍👦‍👦/PXL_20230814_104439655.jpg + 2281660 2024-05-25 22:15 Takeout/Google Photos/🇵🇹 Lisbonne ❤️ en famille 👨‍👩‍👦‍👦/PXL_20230814_105115882.jpg + 858 2024-05-25 22:15 Takeout/Google Photos/🇵🇹 Lisbonne ❤️ en famille 👨‍👩‍👦‍👦/PXL_20230814_120327153.jpg.json + 3784479 2024-05-25 22:15 Takeout/Google Photos/🇵🇹 Lisbonne ❤️ en famille 👨‍👩‍👦‍👦/PXL_20230814_111430712.jpg + 2502925 2024-05-25 22:15 Takeout/Google Photos/🇵🇹 Lisbonne ❤️ en famille 👨‍👩‍👦‍👦/PXL_20230814_113132593.jpg + 2924684 2024-05-25 22:15 Takeout/Google Photos/🇵🇹 Lisbonne ❤️ en famille 👨‍👩‍👦‍👦/PXL_20230814_104311200.jpg + 858 2024-05-25 22:15 Takeout/Google Photos/🇵🇹 Lisbonne ❤️ en famille 👨‍👩‍👦‍👦/PXL_20230814_121239554.jpg.json + 1998148 2024-05-25 22:15 Takeout/Google Photos/🇵🇹 Lisbonne ❤️ en famille 👨‍👩‍👦‍👦/PXL_20230814_113936027.jpg + 842 2024-05-25 22:15 Takeout/Google Photos/🇵🇹 Lisbonne ❤️ en famille 👨‍👩‍👦‍👦/PXL_20230814_120803085.jpg.json + 2280645 2024-05-25 22:15 Takeout/Google Photos/🇵🇹 Lisbonne ❤️ en famille 👨‍👩‍👦‍👦/PXL_20230814_120327153.jpg + 706 2024-05-25 22:15 Takeout/Google Photos/🇵🇹 Lisbonne ❤️ en famille 👨‍👩‍👦‍👦/IMG_1805.HEIC.json + 842 2024-05-25 22:15 Takeout/Google Photos/🇵🇹 Lisbonne ❤️ en famille 👨‍👩‍👦‍👦/PXL_20230814_122023413.jpg.json + 2833588 2024-05-25 22:15 Takeout/Google Photos/🇵🇹 Lisbonne ❤️ en famille 👨‍👩‍👦‍👦/IMG_1809.HEIC + 4079835 2024-05-25 22:15 Takeout/Google Photos/🇵🇹 Lisbonne ❤️ en famille 👨‍👩‍👦‍👦/PXL_20230814_104535388.jpg + 842 2024-05-25 22:15 Takeout/Google Photos/🇵🇹 Lisbonne ❤️ en famille 👨‍👩‍👦‍👦/PXL_20230814_122032538.jpg.json + 3783408 2024-05-25 22:15 Takeout/Google Photos/🇵🇹 Lisbonne ❤️ en famille 👨‍👩‍👦‍👦/IMG_1810.HEIC + 858 2024-05-25 22:15 Takeout/Google Photos/🇵🇹 Lisbonne ❤️ en famille 👨‍👩‍👦‍👦/PXL_20230814_121248049.jpg.json + 2905349 2024-05-25 22:15 Takeout/Google Photos/🇵🇹 Lisbonne ❤️ en famille 👨‍👩‍👦‍👦/PXL_20230814_111310171.jpg + 1664304 2024-05-25 22:15 Takeout/Google Photos/🇵🇹 Lisbonne ❤️ en famille 👨‍👩‍👦‍👦/PXL_20230814_114626362.jpg + 4787027 2024-05-25 22:15 Takeout/Google Photos/🇵🇹 Lisbonne ❤️ en famille 👨‍👩‍👦‍👦/PXL_20230814_104646669.jpg + 850 2024-05-25 22:15 Takeout/Google Photos/🇵🇹 Lisbonne ❤️ en famille 👨‍👩‍👦‍👦/PXL_20230814_134329900.mp4.json + 862 2024-05-25 22:15 Takeout/Google Photos/🇵🇹 Lisbonne ❤️ en famille 👨‍👩‍👦‍👦/PXL_20230814_134755219.jpg.json + 3464559 2024-05-25 22:15 Takeout/Google Photos/🇵🇹 Lisbonne ❤️ en famille 👨‍👩‍👦‍👦/IMG_1811.HEIC + 2879828 2024-05-25 22:15 Takeout/Google Photos/🇵🇹 Lisbonne ❤️ en famille 👨‍👩‍👦‍👦/IMG_1808.HEIC + 1094337 2024-05-25 22:15 Takeout/Google Photos/🇵🇹 Lisbonne ❤️ en famille 👨‍👩‍👦‍👦/IMG_1812.HEIC + 3286583 2024-05-25 22:15 Takeout/Google Photos/🇵🇹 Lisbonne ❤️ en famille 👨‍👩‍👦‍👦/PXL_20230814_121248049.jpg + 706 2024-05-25 22:15 Takeout/Google Photos/🇵🇹 Lisbonne ❤️ en famille 👨‍👩‍👦‍👦/IMG_1808.HEIC.json + 10006046 2024-05-25 22:15 Takeout/Google Photos/🇵🇹 Lisbonne ❤️ en famille 👨‍👩‍👦‍👦/PXL_20230814_085142027.TS.mp4 + 2540915 2024-05-25 22:15 Takeout/Google Photos/🇵🇹 Lisbonne ❤️ en famille 👨‍👩‍👦‍👦/PXL_20230814_120803085.jpg + 2850159 2024-05-25 22:15 Takeout/Google Photos/🇵🇹 Lisbonne ❤️ en famille 👨‍👩‍👦‍👦/PXL_20230814_121239554.jpg + 706 2024-05-25 22:15 Takeout/Google Photos/🇵🇹 Lisbonne ❤️ en famille 👨‍👩‍👦‍👦/IMG_1810.HEIC.json + 706 2024-05-25 22:15 Takeout/Google Photos/🇵🇹 Lisbonne ❤️ en famille 👨‍👩‍👦‍👦/IMG_1809.HEIC.json + 842 2024-05-25 22:15 Takeout/Google Photos/🇵🇹 Lisbonne ❤️ en famille 👨‍👩‍👦‍👦/PXL_20230814_185012667.jpg.json + 858 2024-05-25 22:15 Takeout/Google Photos/🇵🇹 Lisbonne ❤️ en famille 👨‍👩‍👦‍👦/PXL_20230814_191603424.jpg.json + 2829587 2024-05-25 22:15 Takeout/Google Photos/🇵🇹 Lisbonne ❤️ en famille 👨‍👩‍👦‍👦/PXL_20230814_122023413.jpg + 2819007 2024-05-25 22:15 Takeout/Google Photos/🇵🇹 Lisbonne ❤️ en famille 👨‍👩‍👦‍👦/PXL_20230814_122032538.jpg + 842 2024-05-25 22:15 Takeout/Google Photos/🇵🇹 Lisbonne ❤️ en famille 👨‍👩‍👦‍👦/PXL_20230814_185027454.jpg.json + 706 2024-05-25 22:15 Takeout/Google Photos/🇵🇹 Lisbonne ❤️ en famille 👨‍👩‍👦‍👦/IMG_1811.HEIC.json + 860 2024-05-25 22:15 Takeout/Google Photos/🇵🇹 Lisbonne ❤️ en famille 👨‍👩‍👦‍👦/PXL_20230814_191303726.jpg.json + 4694514 2024-05-25 22:15 Takeout/Google Photos/🇵🇹 Lisbonne ❤️ en famille 👨‍👩‍👦‍👦/PXL_20230814_112941866.jpg + 2706891 2024-05-25 22:15 Takeout/Google Photos/🇵🇹 Lisbonne ❤️ en famille 👨‍👩‍👦‍👦/IMG_1814.HEIC + 1474839 2024-05-25 22:15 Takeout/Google Photos/🇵🇹 Lisbonne ❤️ en famille 👨‍👩‍👦‍👦/IMG_1813.HEIC + 858 2024-05-25 22:15 Takeout/Google Photos/🇵🇹 Lisbonne ❤️ en famille 👨‍👩‍👦‍👦/PXL_20230814_191605842.jpg.json + 706 2024-05-25 22:15 Takeout/Google Photos/🇵🇹 Lisbonne ❤️ en famille 👨‍👩‍👦‍👦/IMG_1812.HEIC.json + 2264631 2024-05-25 22:15 Takeout/Google Photos/🇵🇹 Lisbonne ❤️ en famille 👨‍👩‍👦‍👦/PXL_20230814_185012667.jpg + 4497231 2024-05-25 22:15 Takeout/Google Photos/🇵🇹 Lisbonne ❤️ en famille 👨‍👩‍👦‍👦/PXL_20230814_112944670.jpg + 844 2024-05-25 22:15 Takeout/Google Photos/🇵🇹 Lisbonne ❤️ en famille 👨‍👩‍👦‍👦/PXL_20230814_192412458.jpg.json + 706 2024-05-25 22:15 Takeout/Google Photos/🇵🇹 Lisbonne ❤️ en famille 👨‍👩‍👦‍👦/IMG_1813.HEIC.json + 878 2024-05-25 22:15 Takeout/Google Photos/🇵🇹 Lisbonne ❤️ en famille 👨‍👩‍👦‍👦/PXL_20230814_193423423.jpg.json + 878 2024-05-25 22:15 Takeout/Google Photos/🇵🇹 Lisbonne ❤️ en famille 👨‍👩‍👦‍👦/PXL_20230814_193422379.jpg.json + 2385333 2024-05-25 22:15 Takeout/Google Photos/🇵🇹 Lisbonne ❤️ en famille 👨‍👩‍👦‍👦/PXL_20230814_191603424.jpg + 846 2024-05-25 22:15 Takeout/Google Photos/🇵🇹 Lisbonne ❤️ en famille 👨‍👩‍👦‍👦/PXL_20230814_192636406.jpg.json + 2885377 2024-05-25 22:15 Takeout/Google Photos/🇵🇹 Lisbonne ❤️ en famille 👨‍👩‍👦‍👦/IMG_1817.HEIC + 1671841 2024-05-25 22:15 Takeout/Google Photos/🇵🇹 Lisbonne ❤️ en famille 👨‍👩‍👦‍👦/IMG_1815.HEIC + 706 2024-05-25 22:15 Takeout/Google Photos/🇵🇹 Lisbonne ❤️ en famille 👨‍👩‍👦‍👦/IMG_1814.HEIC.json + 844 2024-05-25 22:15 Takeout/Google Photos/🇵🇹 Lisbonne ❤️ en famille 👨‍👩‍👦‍👦/PXL_20230814_194519579.jpg.json + 2712576 2024-05-25 22:15 Takeout/Google Photos/🇵🇹 Lisbonne ❤️ en famille 👨‍👩‍👦‍👦/PXL_20230814_191605842.jpg + 706 2024-05-25 22:15 Takeout/Google Photos/🇵🇹 Lisbonne ❤️ en famille 👨‍👩‍👦‍👦/IMG_1816.HEIC.json + 2917329 2024-05-25 22:15 Takeout/Google Photos/🇵🇹 Lisbonne ❤️ en famille 👨‍👩‍👦‍👦/IMG_1816.HEIC + 4388501 2024-05-25 22:15 Takeout/Google Photos/🇵🇹 Lisbonne ❤️ en famille 👨‍👩‍👦‍👦/PXL_20230814_134755219.jpg + 3456118 2024-05-25 22:15 Takeout/Google Photos/🇵🇹 Lisbonne ❤️ en famille 👨‍👩‍👦‍👦/PXL_20230814_191303726.jpg + 864 2024-05-25 22:15 Takeout/Google Photos/🇵🇹 Lisbonne ❤️ en famille 👨‍👩‍👦‍👦/PXL_20230814_195900654.NIGHT.jpg.json + 844 2024-05-25 22:15 Takeout/Google Photos/🇵🇹 Lisbonne ❤️ en famille 👨‍👩‍👦‍👦/PXL_20230814_195917841.jpg.json + 705 2024-05-25 22:15 Takeout/Google Photos/🇵🇹 Lisbonne ❤️ en famille 👨‍👩‍👦‍👦/IMG_1818.MOV.json + 68756797 2024-05-25 22:15 Takeout/Google Photos/🇵🇹 Lisbonne ❤️ en famille 👨‍👩‍👦‍👦/IMG_1818.MOV + 1804560 2024-05-25 22:15 Takeout/Google Photos/🇵🇹 Lisbonne ❤️ en famille 👨‍👩‍👦‍👦/PXL_20230814_192636406.jpg + 844 2024-05-25 22:15 Takeout/Google Photos/🇵🇹 Lisbonne ❤️ en famille 👨‍👩‍👦‍👦/PXL_20230814_195924456.jpg.json + 706 2024-05-25 22:15 Takeout/Google Photos/🇵🇹 Lisbonne ❤️ en famille 👨‍👩‍👦‍👦/IMG_1815.HEIC.json + 705 2024-05-25 22:15 Takeout/Google Photos/🇵🇹 Lisbonne ❤️ en famille 👨‍👩‍👦‍👦/IMG_1819.MOV.json + 2552809 2024-05-25 22:15 Takeout/Google Photos/🇵🇹 Lisbonne ❤️ en famille 👨‍👩‍👦‍👦/PXL_20230814_193423423.jpg + 706 2024-05-25 22:15 Takeout/Google Photos/🇵🇹 Lisbonne ❤️ en famille 👨‍👩‍👦‍👦/IMG_1817.HEIC.json + 27203198 2024-05-25 22:15 Takeout/Google Photos/🇵🇹 Lisbonne ❤️ en famille 👨‍👩‍👦‍👦/IMG_1819.MOV + 844 2024-05-25 22:15 Takeout/Google Photos/🇵🇹 Lisbonne ❤️ en famille 👨‍👩‍👦‍👦/PXL_20230814_200210541.jpg.json + 2240140 2024-05-25 22:15 Takeout/Google Photos/🇵🇹 Lisbonne ❤️ en famille 👨‍👩‍👦‍👦/PXL_20230814_185027454.jpg + 2500593 2024-05-25 22:15 Takeout/Google Photos/🇵🇹 Lisbonne ❤️ en famille 👨‍👩‍👦‍👦/PXL_20230814_192412458.jpg + 844 2024-05-25 22:15 Takeout/Google Photos/🇵🇹 Lisbonne ❤️ en famille 👨‍👩‍👦‍👦/PXL_20230814_200156149.jpg.json + 842 2024-05-25 22:15 Takeout/Google Photos/🇵🇹 Lisbonne ❤️ en famille 👨‍👩‍👦‍👦/PXL_20230814_200308368.jpg.json + 831 2024-05-25 22:15 Takeout/Google Photos/🇵🇹 Lisbonne ❤️ en famille 👨‍👩‍👦‍👦/PXL_20230814_200310052.TS.mp4.json + 844 2024-05-25 22:15 Takeout/Google Photos/🇵🇹 Lisbonne ❤️ en famille 👨‍👩‍👦‍👦/PXL_20230814_200529292.jpg.json + 2522639 2024-05-25 22:15 Takeout/Google Photos/🇵🇹 Lisbonne ❤️ en famille 👨‍👩‍👦‍👦/PXL_20230814_193422379.jpg + 844 2024-05-25 22:15 Takeout/Google Photos/🇵🇹 Lisbonne ❤️ en famille 👨‍👩‍👦‍👦/PXL_20230814_200532278.jpg.json + 844 2024-05-25 22:15 Takeout/Google Photos/🇵🇹 Lisbonne ❤️ en famille 👨‍👩‍👦‍👦/PXL_20230814_201038861.jpg.json + 3251996 2024-05-25 22:15 Takeout/Google Photos/🇵🇹 Lisbonne ❤️ en famille 👨‍👩‍👦‍👦/PXL_20230814_195924456.jpg + 3499095 2024-05-25 22:15 Takeout/Google Photos/🇵🇹 Lisbonne ❤️ en famille 👨‍👩‍👦‍👦/PXL_20230814_194519579.jpg + 3147675 2024-05-25 22:15 Takeout/Google Photos/🇵🇹 Lisbonne ❤️ en famille 👨‍👩‍👦‍👦/PXL_20230814_195917841.jpg + 804 2024-05-25 22:15 Takeout/Google Photos/🇵🇹 Lisbonne ❤️ en famille 👨‍👩‍👦‍👦/PXL_20230814_201154491.LONG_EXPOSURE-01.COVER..json + 860 2024-05-25 22:15 Takeout/Google Photos/🇵🇹 Lisbonne ❤️ en famille 👨‍👩‍👦‍👦/PXL_20230814_201231937.jpg.json + 844 2024-05-25 22:15 Takeout/Google Photos/🇵🇹 Lisbonne ❤️ en famille 👨‍👩‍👦‍👦/PXL_20230814_201300341.jpg.json + 1749506 2024-05-25 22:15 Takeout/Google Photos/🇵🇹 Lisbonne ❤️ en famille 👨‍👩‍👦‍👦/PXL_20230814_201205358.ACTION_PAN-01.COVER.jpg + 842 2024-05-25 22:15 Takeout/Google Photos/🇵🇹 Lisbonne ❤️ en famille 👨‍👩‍👦‍👦/PXL_20230814_203801941.jpg.json + 801 2024-05-25 22:15 Takeout/Google Photos/🇵🇹 Lisbonne ❤️ en famille 👨‍👩‍👦‍👦/PXL_20230814_201205358.ACTION_PAN-01.COVER.jpg.json + 842 2024-05-25 22:15 Takeout/Google Photos/🇵🇹 Lisbonne ❤️ en famille 👨‍👩‍👦‍👦/PXL_20230814_203823133.jpg.json + 3247533 2024-05-25 22:15 Takeout/Google Photos/🇵🇹 Lisbonne ❤️ en famille 👨‍👩‍👦‍👦/PXL_20230814_195900654.NIGHT.jpg + 842 2024-05-25 22:15 Takeout/Google Photos/🇵🇹 Lisbonne ❤️ en famille 👨‍👩‍👦‍👦/PXL_20230814_203824642.jpg.json + 3727860 2024-05-25 22:15 Takeout/Google Photos/🇵🇹 Lisbonne ❤️ en famille 👨‍👩‍👦‍👦/PXL_20230814_200308368.jpg + 3264214 2024-05-25 22:15 Takeout/Google Photos/🇵🇹 Lisbonne ❤️ en famille 👨‍👩‍👦‍👦/PXL_20230814_200210541.jpg + 842 2024-05-25 22:15 Takeout/Google Photos/🇵🇹 Lisbonne ❤️ en famille 👨‍👩‍👦‍👦/PXL_20230814_203825515.jpg.json + 860 2024-05-25 22:15 Takeout/Google Photos/🇵🇹 Lisbonne ❤️ en famille 👨‍👩‍👦‍👦/PXL_20230814_204729094.jpg.json + 860 2024-05-25 22:15 Takeout/Google Photos/🇵🇹 Lisbonne ❤️ en famille 👨‍👩‍👦‍👦/PXL_20230814_204736848.jpg.json + 3260444 2024-05-25 22:15 Takeout/Google Photos/🇵🇹 Lisbonne ❤️ en famille 👨‍👩‍👦‍👦/PXL_20230814_200156149.jpg + 3721976 2024-05-25 22:15 Takeout/Google Photos/🇵🇹 Lisbonne ❤️ en famille 👨‍👩‍👦‍👦/PXL_20230814_201154491.LONG_EXPOSURE-01.COVER.jpg + 2583993 2024-05-25 22:15 Takeout/Google Photos/🇵🇹 Lisbonne ❤️ en famille 👨‍👩‍👦‍👦/PXL_20230814_200529292.jpg + 12783566 2024-05-25 22:15 Takeout/Google Photos/🇵🇹 Lisbonne ❤️ en famille 👨‍👩‍👦‍👦/PXL_20230814_200310052.TS.mp4 + 843 2024-05-25 22:15 Takeout/Google Photos/🇵🇹 Lisbonne ❤️ en famille 👨‍👩‍👦‍👦/PXL_20230814_203826359.jpg.json + 3227076 2024-05-25 22:15 Takeout/Google Photos/🇵🇹 Lisbonne ❤️ en famille 👨‍👩‍👦‍👦/PXL_20230814_201300341.jpg + 860 2024-05-25 22:15 Takeout/Google Photos/🇵🇹 Lisbonne ❤️ en famille 👨‍👩‍👦‍👦/PXL_20230814_213833167.jpg.json + 3538166 2024-05-25 22:15 Takeout/Google Photos/🇵🇹 Lisbonne ❤️ en famille 👨‍👩‍👦‍👦/PXL_20230814_201038861.jpg + 860 2024-05-25 22:15 Takeout/Google Photos/🇵🇹 Lisbonne ❤️ en famille 👨‍👩‍👦‍👦/PXL_20230814_214029337.jpg.json + 3006962 2024-05-25 22:15 Takeout/Google Photos/🇵🇹 Lisbonne ❤️ en famille 👨‍👩‍👦‍👦/PXL_20230814_203823133.jpg + 860 2024-05-25 22:15 Takeout/Google Photos/🇵🇹 Lisbonne ❤️ en famille 👨‍👩‍👦‍👦/PXL_20230814_214049584.jpg.json + 858 2024-05-25 22:15 Takeout/Google Photos/🇵🇹 Lisbonne ❤️ en famille 👨‍👩‍👦‍👦/PXL_20230814_220414717.jpg.json + 3144573 2024-05-25 22:15 Takeout/Google Photos/🇵🇹 Lisbonne ❤️ en famille 👨‍👩‍👦‍👦/PXL_20230814_203825515.jpg + 2859457 2024-05-25 22:15 Takeout/Google Photos/🇵🇹 Lisbonne ❤️ en famille 👨‍👩‍👦‍👦/PXL_20230814_204736848.jpg + 852 2024-05-25 22:15 Takeout/Google Photos/🇵🇹 Lisbonne ❤️ en famille 👨‍👩‍👦‍👦/PXL_20230814_221244885.NIGHT.jpg.json + 858 2024-05-25 22:15 Takeout/Google Photos/🇵🇹 Lisbonne ❤️ en famille 👨‍👩‍👦‍👦/PXL_20230814_220430652.jpg.json + 16335360 2024-05-25 22:15 Takeout/Google Photos/🇵🇹 Lisbonne ❤️ en famille 👨‍👩‍👦‍👦/IMG_1820.MOV + 3205962 2024-05-25 22:15 Takeout/Google Photos/🇵🇹 Lisbonne ❤️ en famille 👨‍👩‍👦‍👦/PXL_20230814_203801941.jpg + 3638799 2024-05-25 22:15 Takeout/Google Photos/🇵🇹 Lisbonne ❤️ en famille 👨‍👩‍👦‍👦/PXL_20230814_201231937.jpg + 858 2024-05-25 22:15 Takeout/Google Photos/🇵🇹 Lisbonne ❤️ en famille 👨‍👩‍👦‍👦/PXL_20230815_073609646.jpg.json + 860 2024-05-25 22:15 Takeout/Google Photos/🇵🇹 Lisbonne ❤️ en famille 👨‍👩‍👦‍👦/PXL_20230815_092115663.jpg.json + 705 2024-05-25 22:15 Takeout/Google Photos/🇵🇹 Lisbonne ❤️ en famille 👨‍👩‍👦‍👦/IMG_1820.MOV.json + 2950346 2024-05-25 22:15 Takeout/Google Photos/🇵🇹 Lisbonne ❤️ en famille 👨‍👩‍👦‍👦/PXL_20230814_203826359.jpg + 858 2024-05-25 22:15 Takeout/Google Photos/🇵🇹 Lisbonne ❤️ en famille 👨‍👩‍👦‍👦/PXL_20230815_092244364.jpg.json + 3706201 2024-05-25 22:15 Takeout/Google Photos/🇵🇹 Lisbonne ❤️ en famille 👨‍👩‍👦‍👦/PXL_20230814_213833167.jpg + 844 2024-05-25 22:15 Takeout/Google Photos/🇵🇹 Lisbonne ❤️ en famille 👨‍👩‍👦‍👦/PXL_20230815_092314014.jpg.json + 842 2024-05-25 22:15 Takeout/Google Photos/🇵🇹 Lisbonne ❤️ en famille 👨‍👩‍👦‍👦/PXL_20230815_092420813.jpg.json + 3166324 2024-05-25 22:15 Takeout/Google Photos/🇵🇹 Lisbonne ❤️ en famille 👨‍👩‍👦‍👦/PXL_20230814_203824642.jpg + 2076957 2024-05-25 22:15 Takeout/Google Photos/🇵🇹 Lisbonne ❤️ en famille 👨‍👩‍👦‍👦/PXL_20230815_073609646.jpg + 2450989 2024-05-25 22:15 Takeout/Google Photos/🇵🇹 Lisbonne ❤️ en famille 👨‍👩‍👦‍👦/PXL_20230814_200532278.jpg + 2061705 2024-05-25 22:15 Takeout/Google Photos/🇵🇹 Lisbonne ❤️ en famille 👨‍👩‍👦‍👦/PXL_20230814_220414717.jpg + 2711975 2024-05-25 22:15 Takeout/Google Photos/🇵🇹 Lisbonne ❤️ en famille 👨‍👩‍👦‍👦/PXL_20230814_204729094.jpg + 2365786 2024-05-25 22:15 Takeout/Google Photos/🇵🇹 Lisbonne ❤️ en famille 👨‍👩‍👦‍👦/PXL_20230814_220430652.jpg + 1356103 2024-05-25 22:15 Takeout/Google Photos/🇵🇹 Lisbonne ❤️ en famille 👨‍👩‍👦‍👦/PXL_20230814_221244885.NIGHT.jpg + 2929617 2024-05-25 22:15 Takeout/Google Photos/🇵🇹 Lisbonne ❤️ en famille 👨‍👩‍👦‍👦/PXL_20230814_214049584.jpg + 842 2024-05-25 22:15 Takeout/Google Photos/🇵🇹 Lisbonne ❤️ en famille 👨‍👩‍👦‍👦/PXL_20230815_092454769.jpg.json + 860 2024-05-25 22:15 Takeout/Google Photos/🇵🇹 Lisbonne ❤️ en famille 👨‍👩‍👦‍👦/PXL_20230815_092549245.jpg.json + 844 2024-05-25 22:15 Takeout/Google Photos/🇵🇹 Lisbonne ❤️ en famille 👨‍👩‍👦‍👦/PXL_20230815_092559642.jpg.json + 15697268 2024-05-25 22:15 Takeout/Google Photos/🇵🇹 Lisbonne ❤️ en famille 👨‍👩‍👦‍👦/PXL_20230814_134329900.mp4 + 858 2024-05-25 22:15 Takeout/Google Photos/🇵🇹 Lisbonne ❤️ en famille 👨‍👩‍👦‍👦/PXL_20230815_092609468.jpg.json + 842 2024-05-25 22:15 Takeout/Google Photos/🇵🇹 Lisbonne ❤️ en famille 👨‍👩‍👦‍👦/PXL_20230815_092742640.jpg.json + 860 2024-05-25 22:15 Takeout/Google Photos/🇵🇹 Lisbonne ❤️ en famille 👨‍👩‍👦‍👦/PXL_20230815_095719059.jpg.json + 4392195 2024-05-25 22:15 Takeout/Google Photos/🇵🇹 Lisbonne ❤️ en famille 👨‍👩‍👦‍👦/PXL_20230814_214029337.jpg + 3267005 2024-05-25 22:15 Takeout/Google Photos/🇵🇹 Lisbonne ❤️ en famille 👨‍👩‍👦‍👦/PXL_20230815_092314014.jpg + 844 2024-05-25 22:15 Takeout/Google Photos/🇵🇹 Lisbonne ❤️ en famille 👨‍👩‍👦‍👦/PXL_20230815_095911791.jpg.json + 3479639 2024-05-25 22:15 Takeout/Google Photos/🇵🇹 Lisbonne ❤️ en famille 👨‍👩‍👦‍👦/PXL_20230815_092115663.jpg + 842 2024-05-25 22:15 Takeout/Google Photos/🇵🇹 Lisbonne ❤️ en famille 👨‍👩‍👦‍👦/PXL_20230815_110610989.jpg.json + 844 2024-05-25 22:15 Takeout/Google Photos/🇵🇹 Lisbonne ❤️ en famille 👨‍👩‍👦‍👦/PXL_20230815_110716350.jpg.json + 856 2024-05-25 22:15 Takeout/Google Photos/🇵🇹 Lisbonne ❤️ en famille 👨‍👩‍👦‍👦/PXL_20230815_110637215.jpg.json + 842 2024-05-25 22:15 Takeout/Google Photos/🇵🇹 Lisbonne ❤️ en famille 👨‍👩‍👦‍👦/PXL_20230815_110627557.jpg.json + 838 2024-05-25 22:15 Takeout/Google Photos/🇵🇹 Lisbonne ❤️ en famille 👨‍👩‍👦‍👦/PXL_20230815_110956602.jpg.json + 3795394 2024-05-25 22:15 Takeout/Google Photos/🇵🇹 Lisbonne ❤️ en famille 👨‍👩‍👦‍👦/PXL_20230815_092549245.jpg + 856 2024-05-25 22:15 Takeout/Google Photos/🇵🇹 Lisbonne ❤️ en famille 👨‍👩‍👦‍👦/PXL_20230815_110909980.jpg.json + 838 2024-05-25 22:15 Takeout/Google Photos/🇵🇹 Lisbonne ❤️ en famille 👨‍👩‍👦‍👦/PXL_20230815_110958888.jpg.json + 3332616 2024-05-25 22:15 Takeout/Google Photos/🇵🇹 Lisbonne ❤️ en famille 👨‍👩‍👦‍👦/PXL_20230815_092420813.jpg + 2555347 2024-05-25 22:15 Takeout/Google Photos/🇵🇹 Lisbonne ❤️ en famille 👨‍👩‍👦‍👦/PXL_20230815_092559642.jpg + 1104969 2024-05-25 22:15 Takeout/Google Photos/🇵🇹 Lisbonne ❤️ en famille 👨‍👩‍👦‍👦/PXL_20230815_110958888.jpg + 844 2024-05-25 22:15 Takeout/Google Photos/🇵🇹 Lisbonne ❤️ en famille 👨‍👩‍👦‍👦/PXL_20230815_111355138.jpg.json + 2822809 2024-05-25 22:15 Takeout/Google Photos/🇵🇹 Lisbonne ❤️ en famille 👨‍👩‍👦‍👦/IMG_1821.HEIC + 844 2024-05-25 22:15 Takeout/Google Photos/🇵🇹 Lisbonne ❤️ en famille 👨‍👩‍👦‍👦/PXL_20230815_111416343.jpg.json + 842 2024-05-25 22:15 Takeout/Google Photos/🇵🇹 Lisbonne ❤️ en famille 👨‍👩‍👦‍👦/PXL_20230815_111400308.jpg.json + 1477767 2024-05-25 22:15 Takeout/Google Photos/🇵🇹 Lisbonne ❤️ en famille 👨‍👩‍👦‍👦/IMG_1822.HEIC + 4891737 2024-05-25 22:15 Takeout/Google Photos/🇵🇹 Lisbonne ❤️ en famille 👨‍👩‍👦‍👦/PXL_20230815_110610989.jpg + 3257767 2024-05-25 22:15 Takeout/Google Photos/🇵🇹 Lisbonne ❤️ en famille 👨‍👩‍👦‍👦/PXL_20230815_095719059.jpg + 858 2024-05-25 22:15 Takeout/Google Photos/🇵🇹 Lisbonne ❤️ en famille 👨‍👩‍👦‍👦/PXL_20230815_111624099.jpg.json + 860 2024-05-25 22:15 Takeout/Google Photos/🇵🇹 Lisbonne ❤️ en famille 👨‍👩‍👦‍👦/PXL_20230815_111805566.jpg.json + 860 2024-05-25 22:15 Takeout/Google Photos/🇵🇹 Lisbonne ❤️ en famille 👨‍👩‍👦‍👦/PXL_20230815_111809021.jpg.json + 5538289 2024-05-25 22:15 Takeout/Google Photos/🇵🇹 Lisbonne ❤️ en famille 👨‍👩‍👦‍👦/PXL_20230815_092454769.jpg + 2801493 2024-05-25 22:15 Takeout/Google Photos/🇵🇹 Lisbonne ❤️ en famille 👨‍👩‍👦‍👦/PXL_20230815_110956602.jpg + 4236065 2024-05-25 22:15 Takeout/Google Photos/🇵🇹 Lisbonne ❤️ en famille 👨‍👩‍👦‍👦/PXL_20230815_110637215.jpg + 858 2024-05-25 22:15 Takeout/Google Photos/🇵🇹 Lisbonne ❤️ en famille 👨‍👩‍👦‍👦/PXL_20230815_112215507.jpg.json + 3825053 2024-05-25 22:15 Takeout/Google Photos/🇵🇹 Lisbonne ❤️ en famille 👨‍👩‍👦‍👦/PXL_20230815_110909980.jpg + 3882670 2024-05-25 22:15 Takeout/Google Photos/🇵🇹 Lisbonne ❤️ en famille 👨‍👩‍👦‍👦/PXL_20230815_095911791.jpg + 706 2024-05-25 22:15 Takeout/Google Photos/🇵🇹 Lisbonne ❤️ en famille 👨‍👩‍👦‍👦/IMG_1821.HEIC.json + 3682575 2024-05-25 22:15 Takeout/Google Photos/🇵🇹 Lisbonne ❤️ en famille 👨‍👩‍👦‍👦/PXL_20230815_111400308.jpg + 706 2024-05-25 22:15 Takeout/Google Photos/🇵🇹 Lisbonne ❤️ en famille 👨‍👩‍👦‍👦/IMG_1822.HEIC.json + 4421482 2024-05-25 22:15 Takeout/Google Photos/🇵🇹 Lisbonne ❤️ en famille 👨‍👩‍👦‍👦/PXL_20230815_092609468.jpg + 3807495 2024-05-25 22:15 Takeout/Google Photos/🇵🇹 Lisbonne ❤️ en famille 👨‍👩‍👦‍👦/PXL_20230815_110627557.jpg + 1406035 2024-05-25 22:15 Takeout/Google Photos/🇵🇹 Lisbonne ❤️ en famille 👨‍👩‍👦‍👦/IMG_1826.HEIC + 5056540 2024-05-25 22:15 Takeout/Google Photos/🇵🇹 Lisbonne ❤️ en famille 👨‍👩‍👦‍👦/PXL_20230815_092742640.jpg + 876 2024-05-25 22:15 Takeout/Google Photos/🇵🇹 Lisbonne ❤️ en famille 👨‍👩‍👦‍👦/PXL_20230815_112252009.jpg.json + 840 2024-05-25 22:15 Takeout/Google Photos/🇵🇹 Lisbonne ❤️ en famille 👨‍👩‍👦‍👦/PXL_20230815_112349398.jpg.json + 844 2024-05-25 22:15 Takeout/Google Photos/🇵🇹 Lisbonne ❤️ en famille 👨‍👩‍👦‍👦/PXL_20230815_112447598.jpg.json + 3655827 2024-05-25 22:15 Takeout/Google Photos/🇵🇹 Lisbonne ❤️ en famille 👨‍👩‍👦‍👦/PXL_20230815_111355138.jpg + 2021117 2024-05-25 22:15 Takeout/Google Photos/🇵🇹 Lisbonne ❤️ en famille 👨‍👩‍👦‍👦/IMG_1824.HEIC + 2928784 2024-05-25 22:15 Takeout/Google Photos/🇵🇹 Lisbonne ❤️ en famille 👨‍👩‍👦‍👦/PXL_20230815_111809021.jpg + 874 2024-05-25 22:15 Takeout/Google Photos/🇵🇹 Lisbonne ❤️ en famille 👨‍👩‍👦‍👦/PXL_20230815_112517602.jpg.json + 3280542 2024-05-25 22:15 Takeout/Google Photos/🇵🇹 Lisbonne ❤️ en famille 👨‍👩‍👦‍👦/PXL_20230815_111416343.jpg + 706 2024-05-25 22:15 Takeout/Google Photos/🇵🇹 Lisbonne ❤️ en famille 👨‍👩‍👦‍👦/IMG_1823.HEIC.json + 2752273 2024-05-25 22:15 Takeout/Google Photos/🇵🇹 Lisbonne ❤️ en famille 👨‍👩‍👦‍👦/PXL_20230815_111805566.jpg + 858 2024-05-25 22:15 Takeout/Google Photos/🇵🇹 Lisbonne ❤️ en famille 👨‍👩‍👦‍👦/PXL_20230815_113519297.jpg.json + 3392793 2024-05-25 22:15 Takeout/Google Photos/🇵🇹 Lisbonne ❤️ en famille 👨‍👩‍👦‍👦/IMG_1823.HEIC + 3234964 2024-05-25 22:15 Takeout/Google Photos/🇵🇹 Lisbonne ❤️ en famille 👨‍👩‍👦‍👦/PXL_20230815_112215507.jpg + 860 2024-05-25 22:15 Takeout/Google Photos/🇵🇹 Lisbonne ❤️ en famille 👨‍👩‍👦‍👦/PXL_20230815_114315562.jpg.json + 2672206 2024-05-25 22:15 Takeout/Google Photos/🇵🇹 Lisbonne ❤️ en famille 👨‍👩‍👦‍👦/PXL_20230815_112252009.jpg + 1902366 2024-05-25 22:15 Takeout/Google Photos/🇵🇹 Lisbonne ❤️ en famille 👨‍👩‍👦‍👦/IMG_1829.HEIC + 706 2024-05-25 22:15 Takeout/Google Photos/🇵🇹 Lisbonne ❤️ en famille 👨‍👩‍👦‍👦/IMG_1826.HEIC.json + 706 2024-05-25 22:15 Takeout/Google Photos/🇵🇹 Lisbonne ❤️ en famille 👨‍👩‍👦‍👦/IMG_1825.HEIC.json + 706 2024-05-25 22:15 Takeout/Google Photos/🇵🇹 Lisbonne ❤️ en famille 👨‍👩‍👦‍👦/IMG_1824.HEIC.json + 858 2024-05-25 22:15 Takeout/Google Photos/🇵🇹 Lisbonne ❤️ en famille 👨‍👩‍👦‍👦/PXL_20230815_114438496.jpg.json + 706 2024-05-25 22:15 Takeout/Google Photos/🇵🇹 Lisbonne ❤️ en famille 👨‍👩‍👦‍👦/IMG_1827.HEIC.json + 844 2024-05-25 22:15 Takeout/Google Photos/🇵🇹 Lisbonne ❤️ en famille 👨‍👩‍👦‍👦/PXL_20230815_114334732.jpg.json + 4857728 2024-05-25 22:15 Takeout/Google Photos/🇵🇹 Lisbonne ❤️ en famille 👨‍👩‍👦‍👦/PXL_20230815_111624099.jpg + 842 2024-05-25 22:15 Takeout/Google Photos/🇵🇹 Lisbonne ❤️ en famille 👨‍👩‍👦‍👦/PXL_20230815_114451718.jpg.json + 1590243 2024-05-25 22:15 Takeout/Google Photos/🇵🇹 Lisbonne ❤️ en famille 👨‍👩‍👦‍👦/IMG_1828.HEIC + 706 2024-05-25 22:15 Takeout/Google Photos/🇵🇹 Lisbonne ❤️ en famille 👨‍👩‍👦‍👦/IMG_1828.HEIC.json + 3276096 2024-05-25 22:15 Takeout/Google Photos/🇵🇹 Lisbonne ❤️ en famille 👨‍👩‍👦‍👦/PXL_20230815_112517602.jpg + 2207069 2024-05-25 22:15 Takeout/Google Photos/🇵🇹 Lisbonne ❤️ en famille 👨‍👩‍👦‍👦/PXL_20230815_092244364.jpg + 706 2024-05-25 22:15 Takeout/Google Photos/🇵🇹 Lisbonne ❤️ en famille 👨‍👩‍👦‍👦/IMG_1829.HEIC.json + 2880413 2024-05-25 22:15 Takeout/Google Photos/🇵🇹 Lisbonne ❤️ en famille 👨‍👩‍👦‍👦/IMG_1827.HEIC + 4622459 2024-05-25 22:15 Takeout/Google Photos/🇵🇹 Lisbonne ❤️ en famille 👨‍👩‍👦‍👦/PXL_20230815_110716350.jpg + 860 2024-05-25 22:15 Takeout/Google Photos/🇵🇹 Lisbonne ❤️ en famille 👨‍👩‍👦‍👦/PXL_20230815_114603834.jpg.json + 4107927 2024-05-25 22:15 Takeout/Google Photos/🇵🇹 Lisbonne ❤️ en famille 👨‍👩‍👦‍👦/PXL_20230815_112349398.jpg + 874 2024-05-25 22:15 Takeout/Google Photos/🇵🇹 Lisbonne ❤️ en famille 👨‍👩‍👦‍👦/PXL_20230815_114655917.jpg.json + 1858441 2024-05-25 22:15 Takeout/Google Photos/🇵🇹 Lisbonne ❤️ en famille 👨‍👩‍👦‍👦/IMG_1825.HEIC + 1230898 2024-05-25 22:15 Takeout/Google Photos/🇵🇹 Lisbonne ❤️ en famille 👨‍👩‍👦‍👦/PXL_20230815_114941122.jpg + 2329548 2024-05-25 22:15 Takeout/Google Photos/🇵🇹 Lisbonne ❤️ en famille 👨‍👩‍👦‍👦/PXL_20230815_114334732.jpg + 3027958 2024-05-25 22:15 Takeout/Google Photos/🇵🇹 Lisbonne ❤️ en famille 👨‍👩‍👦‍👦/PXL_20230815_113519297.jpg + 852 2024-05-25 22:15 Takeout/Google Photos/🇵🇹 Lisbonne ❤️ en famille 👨‍👩‍👦‍👦/PXL_20230815_114708377.jpg.json + 4163914 2024-05-25 22:15 Takeout/Google Photos/🇵🇹 Lisbonne ❤️ en famille 👨‍👩‍👦‍👦/PXL_20230815_112447598.jpg + 1288661 2024-05-25 22:15 Takeout/Google Photos/🇵🇹 Lisbonne ❤️ en famille 👨‍👩‍👦‍👦/IMG_1831.HEIC + 844 2024-05-25 22:15 Takeout/Google Photos/🇵🇹 Lisbonne ❤️ en famille 👨‍👩‍👦‍👦/PXL_20230815_114849873.jpg.json + 1755648 2024-05-25 22:15 Takeout/Google Photos/🇵🇹 Lisbonne ❤️ en famille 👨‍👩‍👦‍👦/PXL_20230815_114438496.jpg + 3186118 2024-05-25 22:15 Takeout/Google Photos/🇵🇹 Lisbonne ❤️ en famille 👨‍👩‍👦‍👦/IMG_1832.HEIC + 844 2024-05-25 22:15 Takeout/Google Photos/🇵🇹 Lisbonne ❤️ en famille 👨‍👩‍👦‍👦/PXL_20230815_114750722.jpg.json + 860 2024-05-25 22:15 Takeout/Google Photos/🇵🇹 Lisbonne ❤️ en famille 👨‍👩‍👦‍👦/PXL_20230815_115247743.jpg.json + 858 2024-05-25 22:15 Takeout/Google Photos/🇵🇹 Lisbonne ❤️ en famille 👨‍👩‍👦‍👦/PXL_20230815_114941122.jpg.json + 842 2024-05-25 22:15 Takeout/Google Photos/🇵🇹 Lisbonne ❤️ en famille 👨‍👩‍👦‍👦/PXL_20230815_115339983.jpg.json + 858 2024-05-25 22:15 Takeout/Google Photos/🇵🇹 Lisbonne ❤️ en famille 👨‍👩‍👦‍👦/PXL_20230815_115324982.jpg.json + 2281324 2024-05-25 22:15 Takeout/Google Photos/🇵🇹 Lisbonne ❤️ en famille 👨‍👩‍👦‍👦/IMG_1830.HEIC + 842 2024-05-25 22:15 Takeout/Google Photos/🇵🇹 Lisbonne ❤️ en famille 👨‍👩‍👦‍👦/PXL_20230815_115341662.jpg.json + 2817633 2024-05-25 22:15 Takeout/Google Photos/🇵🇹 Lisbonne ❤️ en famille 👨‍👩‍👦‍👦/PXL_20230815_114603834.jpg + 706 2024-05-25 22:15 Takeout/Google Photos/🇵🇹 Lisbonne ❤️ en famille 👨‍👩‍👦‍👦/IMG_1831.HEIC.json + 3084847 2024-05-25 22:15 Takeout/Google Photos/🇵🇹 Lisbonne ❤️ en famille 👨‍👩‍👦‍👦/PXL_20230815_114849873.jpg + 2159034 2024-05-25 22:15 Takeout/Google Photos/🇵🇹 Lisbonne ❤️ en famille 👨‍👩‍👦‍👦/IMG_1835.HEIC + 706 2024-05-25 22:15 Takeout/Google Photos/🇵🇹 Lisbonne ❤️ en famille 👨‍👩‍👦‍👦/IMG_1832.HEIC.json + 3083608 2024-05-25 22:15 Takeout/Google Photos/🇵🇹 Lisbonne ❤️ en famille 👨‍👩‍👦‍👦/IMG_1833.HEIC + 830653 2024-05-25 22:15 Takeout/Google Photos/🇵🇹 Lisbonne ❤️ en famille 👨‍👩‍👦‍👦/PXL_20230815_115247743.jpg + 706 2024-05-25 22:15 Takeout/Google Photos/🇵🇹 Lisbonne ❤️ en famille 👨‍👩‍👦‍👦/IMG_1833.HEIC.json + 706 2024-05-25 22:15 Takeout/Google Photos/🇵🇹 Lisbonne ❤️ en famille 👨‍👩‍👦‍👦/IMG_1830.HEIC.json + 706 2024-05-25 22:15 Takeout/Google Photos/🇵🇹 Lisbonne ❤️ en famille 👨‍👩‍👦‍👦/IMG_1834.HEIC.json + 1571401 2024-05-25 22:15 Takeout/Google Photos/🇵🇹 Lisbonne ❤️ en famille 👨‍👩‍👦‍👦/IMG_1834.HEIC + 2711792 2024-05-25 22:15 Takeout/Google Photos/🇵🇹 Lisbonne ❤️ en famille 👨‍👩‍👦‍👦/IMG_1836.HEIC + 1995263 2024-05-25 22:15 Takeout/Google Photos/🇵🇹 Lisbonne ❤️ en famille 👨‍👩‍👦‍👦/PXL_20230815_114708377.jpg + 4297880 2024-05-25 22:15 Takeout/Google Photos/🇵🇹 Lisbonne ❤️ en famille 👨‍👩‍👦‍👦/PXL_20230815_114451718.jpg + 2672283 2024-05-25 22:15 Takeout/Google Photos/🇵🇹 Lisbonne ❤️ en famille 👨‍👩‍👦‍👦/PXL_20230815_114655917.jpg + 844 2024-05-25 22:15 Takeout/Google Photos/🇵🇹 Lisbonne ❤️ en famille 👨‍👩‍👦‍👦/PXL_20230815_121631092.jpg.json + 2200132 2024-05-25 22:15 Takeout/Google Photos/🇵🇹 Lisbonne ❤️ en famille 👨‍👩‍👦‍👦/PXL_20230815_115341662.jpg + 706 2024-05-25 22:15 Takeout/Google Photos/🇵🇹 Lisbonne ❤️ en famille 👨‍👩‍👦‍👦/IMG_1835.HEIC.json + 844 2024-05-25 22:15 Takeout/Google Photos/🇵🇹 Lisbonne ❤️ en famille 👨‍👩‍👦‍👦/PXL_20230815_121633187.jpg.json + 842 2024-05-25 22:15 Takeout/Google Photos/🇵🇹 Lisbonne ❤️ en famille 👨‍👩‍👦‍👦/PXL_20230815_122137232.jpg.json + 2085527 2024-05-25 22:15 Takeout/Google Photos/🇵🇹 Lisbonne ❤️ en famille 👨‍👩‍👦‍👦/PXL_20230815_115339983.jpg + 842 2024-05-25 22:15 Takeout/Google Photos/🇵🇹 Lisbonne ❤️ en famille 👨‍👩‍👦‍👦/PXL_20230815_122826011.jpg.json + 2189884 2024-05-25 22:15 Takeout/Google Photos/🇵🇹 Lisbonne ❤️ en famille 👨‍👩‍👦‍👦/PXL_20230815_122137232.jpg + 706 2024-05-25 22:15 Takeout/Google Photos/🇵🇹 Lisbonne ❤️ en famille 👨‍👩‍👦‍👦/IMG_1836.HEIC.json + 2463125 2024-05-25 22:15 Takeout/Google Photos/🇵🇹 Lisbonne ❤️ en famille 👨‍👩‍👦‍👦/IMG_1837.HEIC + 1882389 2024-05-25 22:15 Takeout/Google Photos/🇵🇹 Lisbonne ❤️ en famille 👨‍👩‍👦‍👦/PXL_20230815_121631092.jpg + 858 2024-05-25 22:15 Takeout/Google Photos/🇵🇹 Lisbonne ❤️ en famille 👨‍👩‍👦‍👦/PXL_20230815_122926905.jpg.json + 842 2024-05-25 22:15 Takeout/Google Photos/🇵🇹 Lisbonne ❤️ en famille 👨‍👩‍👦‍👦/PXL_20230815_123051917.jpg.json + 2471414 2024-05-25 22:15 Takeout/Google Photos/🇵🇹 Lisbonne ❤️ en famille 👨‍👩‍👦‍👦/IMG_1838.HEIC + 842 2024-05-25 22:15 Takeout/Google Photos/🇵🇹 Lisbonne ❤️ en famille 👨‍👩‍👦‍👦/PXL_20230815_123055666.jpg.json + 1721502 2024-05-25 22:15 Takeout/Google Photos/🇵🇹 Lisbonne ❤️ en famille 👨‍👩‍👦‍👦/PXL_20230815_114750722.jpg + 2282623 2024-05-25 22:15 Takeout/Google Photos/🇵🇹 Lisbonne ❤️ en famille 👨‍👩‍👦‍👦/PXL_20230815_115324982.jpg + 842 2024-05-25 22:15 Takeout/Google Photos/🇵🇹 Lisbonne ❤️ en famille 👨‍👩‍👦‍👦/PXL_20230815_123109118.jpg.json + 858 2024-05-25 22:15 Takeout/Google Photos/🇵🇹 Lisbonne ❤️ en famille 👨‍👩‍👦‍👦/PXL_20230815_123314870.jpg.json + 1865198 2024-05-25 22:15 Takeout/Google Photos/🇵🇹 Lisbonne ❤️ en famille 👨‍👩‍👦‍👦/IMG_1839.HEIC + 853 2024-05-25 22:15 Takeout/Google Photos/🇵🇹 Lisbonne ❤️ en famille 👨‍👩‍👦‍👦/PXL_20230815_124031987.TS.mp4.json + 844 2024-05-25 22:15 Takeout/Google Photos/🇵🇹 Lisbonne ❤️ en famille 👨‍👩‍👦‍👦/PXL_20230815_123624823.jpg.json + 706 2024-05-25 22:15 Takeout/Google Photos/🇵🇹 Lisbonne ❤️ en famille 👨‍👩‍👦‍👦/IMG_1837.HEIC.json + 2772827 2024-05-25 22:15 Takeout/Google Photos/🇵🇹 Lisbonne ❤️ en famille 👨‍👩‍👦‍👦/PXL_20230815_123109118.jpg + 2347070 2024-05-25 22:15 Takeout/Google Photos/🇵🇹 Lisbonne ❤️ en famille 👨‍👩‍👦‍👦/PXL_20230815_122926905.jpg + 876 2024-05-25 22:15 Takeout/Google Photos/🇵🇹 Lisbonne ❤️ en famille 👨‍👩‍👦‍👦/PXL_20230815_124552627.PORTRAIT.ORIGINAL.jpg.json + 1953026 2024-05-25 22:15 Takeout/Google Photos/🇵🇹 Lisbonne ❤️ en famille 👨‍👩‍👦‍👦/PXL_20230815_121633187.jpg + 706 2024-05-25 22:15 Takeout/Google Photos/🇵🇹 Lisbonne ❤️ en famille 👨‍👩‍👦‍👦/IMG_1838.HEIC.json + 1738977 2024-05-25 22:15 Takeout/Google Photos/🇵🇹 Lisbonne ❤️ en famille 👨‍👩‍👦‍👦/PXL_20230815_114315562.jpg + 867 2024-05-25 22:15 Takeout/Google Photos/🇵🇹 Lisbonne ❤️ en famille 👨‍👩‍👦‍👦/PXL_20230815_124817964.PORTRAIT.jpg.json + 860 2024-05-25 22:15 Takeout/Google Photos/🇵🇹 Lisbonne ❤️ en famille 👨‍👩‍👦‍👦/PXL_20230815_124911036.jpg.json + 5106360 2024-05-25 22:15 Takeout/Google Photos/🇵🇹 Lisbonne ❤️ en famille 👨‍👩‍👦‍👦/PXL_20230815_124817964.PORTRAIT.jpg + 1700453 2024-05-25 22:15 Takeout/Google Photos/🇵🇹 Lisbonne ❤️ en famille 👨‍👩‍👦‍👦/IMG_1842.HEIC + 3246872 2024-05-25 22:15 Takeout/Google Photos/🇵🇹 Lisbonne ❤️ en famille 👨‍👩‍👦‍👦/PXL_20230815_122826011.jpg + 706 2024-05-25 22:15 Takeout/Google Photos/🇵🇹 Lisbonne ❤️ en famille 👨‍👩‍👦‍👦/IMG_1839.HEIC.json + 1281223 2024-05-25 22:15 Takeout/Google Photos/🇵🇹 Lisbonne ❤️ en famille 👨‍👩‍👦‍👦/IMG_1840.HEIC + 706 2024-05-25 22:15 Takeout/Google Photos/🇵🇹 Lisbonne ❤️ en famille 👨‍👩‍👦‍👦/IMG_1840.HEIC.json + 858 2024-05-25 22:15 Takeout/Google Photos/🇵🇹 Lisbonne ❤️ en famille 👨‍👩‍👦‍👦/PXL_20230815_125508511.jpg.json + 2744968 2024-05-25 22:15 Takeout/Google Photos/🇵🇹 Lisbonne ❤️ en famille 👨‍👩‍👦‍👦/PXL_20230815_123051917.jpg + 1731604 2024-05-25 22:15 Takeout/Google Photos/🇵🇹 Lisbonne ❤️ en famille 👨‍👩‍👦‍👦/PXL_20230815_123314870.jpg + 2988456 2024-05-25 22:15 Takeout/Google Photos/🇵🇹 Lisbonne ❤️ en famille 👨‍👩‍👦‍👦/PXL_20230815_123055666.jpg + 1801212 2024-05-25 22:15 Takeout/Google Photos/🇵🇹 Lisbonne ❤️ en famille 👨‍👩‍👦‍👦/IMG_1841.HEIC + 858 2024-05-25 22:15 Takeout/Google Photos/🇵🇹 Lisbonne ❤️ en famille 👨‍👩‍👦‍👦/PXL_20230815_125516847.jpg.json + 706 2024-05-25 22:15 Takeout/Google Photos/🇵🇹 Lisbonne ❤️ en famille 👨‍👩‍👦‍👦/IMG_1841.HEIC.json + 1325046 2024-05-25 22:15 Takeout/Google Photos/🇵🇹 Lisbonne ❤️ en famille 👨‍👩‍👦‍👦/PXL_20230815_124031987.TS.mp4 + 2189746 2024-05-25 22:15 Takeout/Google Photos/🇵🇹 Lisbonne ❤️ en famille 👨‍👩‍👦‍👦/IMG_1843.HEIC + 2503191 2024-05-25 22:15 Takeout/Google Photos/🇵🇹 Lisbonne ❤️ en famille 👨‍👩‍👦‍👦/IMG_1844.HEIC + 706 2024-05-25 22:15 Takeout/Google Photos/🇵🇹 Lisbonne ❤️ en famille 👨‍👩‍👦‍👦/IMG_1842.HEIC.json + 2452627 2024-05-25 22:15 Takeout/Google Photos/🇵🇹 Lisbonne ❤️ en famille 👨‍👩‍👦‍👦/PXL_20230815_123624823.jpg + 831 2024-05-25 22:15 Takeout/Google Photos/🇵🇹 Lisbonne ❤️ en famille 👨‍👩‍👦‍👦/PXL_20230815_125540275.TS.mp4.json + 2722453 2024-05-25 22:15 Takeout/Google Photos/🇵🇹 Lisbonne ❤️ en famille 👨‍👩‍👦‍👦/PXL_20230815_124552627.PORTRAIT.ORIGINAL.jpg + 836 2024-05-25 22:15 Takeout/Google Photos/🇵🇹 Lisbonne ❤️ en famille 👨‍👩‍👦‍👦/PXL_20230815_125637640.jpg.json + 2530601 2024-05-25 22:15 Takeout/Google Photos/🇵🇹 Lisbonne ❤️ en famille 👨‍👩‍👦‍👦/IMG_1845.HEIC + 836 2024-05-25 22:15 Takeout/Google Photos/🇵🇹 Lisbonne ❤️ en famille 👨‍👩‍👦‍👦/PXL_20230815_125646665.jpg.json + 2806033 2024-05-25 22:15 Takeout/Google Photos/🇵🇹 Lisbonne ❤️ en famille 👨‍👩‍👦‍👦/IMG_1848.HEIC + 874 2024-05-25 22:15 Takeout/Google Photos/🇵🇹 Lisbonne ❤️ en famille 👨‍👩‍👦‍👦/PXL_20230815_125905261.PORTRAIT.ORIGINAL.jpg.json + 706 2024-05-25 22:15 Takeout/Google Photos/🇵🇹 Lisbonne ❤️ en famille 👨‍👩‍👦‍👦/IMG_1844.HEIC.json + 2739332 2024-05-25 22:15 Takeout/Google Photos/🇵🇹 Lisbonne ❤️ en famille 👨‍👩‍👦‍👦/PXL_20230815_124911036.jpg + 706 2024-05-25 22:15 Takeout/Google Photos/🇵🇹 Lisbonne ❤️ en famille 👨‍👩‍👦‍👦/IMG_1843.HEIC.json + 2576854 2024-05-25 22:15 Takeout/Google Photos/🇵🇹 Lisbonne ❤️ en famille 👨‍👩‍👦‍👦/IMG_1846.HEIC + 706 2024-05-25 22:15 Takeout/Google Photos/🇵🇹 Lisbonne ❤️ en famille 👨‍👩‍👦‍👦/IMG_1845.HEIC.json + 3078212 2024-05-25 22:15 Takeout/Google Photos/🇵🇹 Lisbonne ❤️ en famille 👨‍👩‍👦‍👦/PXL_20230815_125516847.jpg + 2309189 2024-05-25 22:15 Takeout/Google Photos/🇵🇹 Lisbonne ❤️ en famille 👨‍👩‍👦‍👦/IMG_1847.HEIC + 860 2024-05-25 22:15 Takeout/Google Photos/🇵🇹 Lisbonne ❤️ en famille 👨‍👩‍👦‍👦/PXL_20230815_130155836.PORTRAIT.ORIGINAL.jpg.json + 706 2024-05-25 22:15 Takeout/Google Photos/🇵🇹 Lisbonne ❤️ en famille 👨‍👩‍👦‍👦/IMG_1846.HEIC.json + 706 2024-05-25 22:15 Takeout/Google Photos/🇵🇹 Lisbonne ❤️ en famille 👨‍👩‍👦‍👦/IMG_1848.HEIC.json + 842 2024-05-25 22:15 Takeout/Google Photos/🇵🇹 Lisbonne ❤️ en famille 👨‍👩‍👦‍👦/PXL_20230815_130631866.jpg.json + 2747390 2024-05-25 22:15 Takeout/Google Photos/🇵🇹 Lisbonne ❤️ en famille 👨‍👩‍👦‍👦/PXL_20230815_125646665.jpg + 706 2024-05-25 22:15 Takeout/Google Photos/🇵🇹 Lisbonne ❤️ en famille 👨‍👩‍👦‍👦/IMG_1847.HEIC.json + 874 2024-05-25 22:15 Takeout/Google Photos/🇵🇹 Lisbonne ❤️ en famille 👨‍👩‍👦‍👦/PXL_20230815_131013972.jpg.json + 874 2024-05-25 22:15 Takeout/Google Photos/🇵🇹 Lisbonne ❤️ en famille 👨‍👩‍👦‍👦/PXL_20230815_131100760.jpg.json + 874 2024-05-25 22:15 Takeout/Google Photos/🇵🇹 Lisbonne ❤️ en famille 👨‍👩‍👦‍👦/PXL_20230815_131020934.jpg.json + 2787837 2024-05-25 22:15 Takeout/Google Photos/🇵🇹 Lisbonne ❤️ en famille 👨‍👩‍👦‍👦/PXL_20230815_125508511.jpg + 2213164 2024-05-25 22:15 Takeout/Google Photos/🇵🇹 Lisbonne ❤️ en famille 👨‍👩‍👦‍👦/PXL_20230815_125905261.PORTRAIT.ORIGINAL.jpg + 858 2024-05-25 22:15 Takeout/Google Photos/🇵🇹 Lisbonne ❤️ en famille 👨‍👩‍👦‍👦/PXL_20230815_132140303.jpg.json + 858 2024-05-25 22:15 Takeout/Google Photos/🇵🇹 Lisbonne ❤️ en famille 👨‍👩‍👦‍👦/PXL_20230815_132154767.jpg.json + 856 2024-05-25 22:15 Takeout/Google Photos/🇵🇹 Lisbonne ❤️ en famille 👨‍👩‍👦‍👦/PXL_20230815_132231336.jpg.json + 845 2024-05-25 22:15 Takeout/Google Photos/🇵🇹 Lisbonne ❤️ en famille 👨‍👩‍👦‍👦/PXL_20230815_150752249.PANO.jpg.json + 844 2024-05-25 22:15 Takeout/Google Photos/🇵🇹 Lisbonne ❤️ en famille 👨‍👩‍👦‍👦/PXL_20230815_152254524.jpg.json + 860 2024-05-25 22:15 Takeout/Google Photos/🇵🇹 Lisbonne ❤️ en famille 👨‍👩‍👦‍👦/PXL_20230815_151238032.jpg.json + 876 2024-05-25 22:15 Takeout/Google Photos/🇵🇹 Lisbonne ❤️ en famille 👨‍👩‍👦‍👦/PXL_20230815_152303067.jpg.json + 2479158 2024-05-25 22:15 Takeout/Google Photos/🇵🇹 Lisbonne ❤️ en famille 👨‍👩‍👦‍👦/PXL_20230815_130631866.jpg + 3184937 2024-05-25 22:15 Takeout/Google Photos/🇵🇹 Lisbonne ❤️ en famille 👨‍👩‍👦‍👦/PXL_20230815_132140303.jpg + 3051320 2024-05-25 22:15 Takeout/Google Photos/🇵🇹 Lisbonne ❤️ en famille 👨‍👩‍👦‍👦/PXL_20230815_130155836.PORTRAIT.ORIGINAL.jpg + 860 2024-05-25 22:15 Takeout/Google Photos/🇵🇹 Lisbonne ❤️ en famille 👨‍👩‍👦‍👦/PXL_20230815_152405874.jpg.json + 842 2024-05-25 22:15 Takeout/Google Photos/🇵🇹 Lisbonne ❤️ en famille 👨‍👩‍👦‍👦/PXL_20230815_152841555.jpg.json + 5022885 2024-05-25 22:15 Takeout/Google Photos/🇵🇹 Lisbonne ❤️ en famille 👨‍👩‍👦‍👦/PXL_20230815_131013972.jpg + 860 2024-05-25 22:15 Takeout/Google Photos/🇵🇹 Lisbonne ❤️ en famille 👨‍👩‍👦‍👦/PXL_20230815_152846037.jpg.json + 862 2024-05-25 22:15 Takeout/Google Photos/🇵🇹 Lisbonne ❤️ en famille 👨‍👩‍👦‍👦/PXL_20230815_152846037~2.jpg.json + 862 2024-05-25 22:15 Takeout/Google Photos/🇵🇹 Lisbonne ❤️ en famille 👨‍👩‍👦‍👦/PXL_20230815_153003181~3.jpg.json + 4805476 2024-05-25 22:15 Takeout/Google Photos/🇵🇹 Lisbonne ❤️ en famille 👨‍👩‍👦‍👦/PXL_20230815_131020934.jpg + 899 2024-05-25 22:15 Takeout/Google Photos/🇵🇹 Lisbonne ❤️ en famille 👨‍👩‍👦‍👦/PXL_20230815_153003181~2.jpg.json + 844 2024-05-25 22:15 Takeout/Google Photos/🇵🇹 Lisbonne ❤️ en famille 👨‍👩‍👦‍👦/PXL_20230815_153110793.jpg.json + 842 2024-05-25 22:15 Takeout/Google Photos/🇵🇹 Lisbonne ❤️ en famille 👨‍👩‍👦‍👦/PXL_20230815_153308948.jpg.json + 860 2024-05-25 22:15 Takeout/Google Photos/🇵🇹 Lisbonne ❤️ en famille 👨‍👩‍👦‍👦/PXL_20230815_153003181.jpg.json + 858 2024-05-25 22:15 Takeout/Google Photos/🇵🇹 Lisbonne ❤️ en famille 👨‍👩‍👦‍👦/PXL_20230815_153603660.jpg.json + 842 2024-05-25 22:15 Takeout/Google Photos/🇵🇹 Lisbonne ❤️ en famille 👨‍👩‍👦‍👦/PXL_20230815_153359013.jpg.json + 842 2024-05-25 22:15 Takeout/Google Photos/🇵🇹 Lisbonne ❤️ en famille 👨‍👩‍👦‍👦/PXL_20230815_155435571.jpg.json + 842 2024-05-25 22:15 Takeout/Google Photos/🇵🇹 Lisbonne ❤️ en famille 👨‍👩‍👦‍👦/PXL_20230815_155505084.jpg.json + 842 2024-05-25 22:15 Takeout/Google Photos/🇵🇹 Lisbonne ❤️ en famille 👨‍👩‍👦‍👦/PXL_20230815_160052888.jpg.json + 706 2024-05-25 22:15 Takeout/Google Photos/🇵🇹 Lisbonne ❤️ en famille 👨‍👩‍👦‍👦/IMG_1849.HEIC.json + 842 2024-05-25 22:15 Takeout/Google Photos/🇵🇹 Lisbonne ❤️ en famille 👨‍👩‍👦‍👦/PXL_20230815_160105481.jpg.json + 860 2024-05-25 22:15 Takeout/Google Photos/🇵🇹 Lisbonne ❤️ en famille 👨‍👩‍👦‍👦/PXL_20230815_160831688.jpg.json + 842 2024-05-25 22:15 Takeout/Google Photos/🇵🇹 Lisbonne ❤️ en famille 👨‍👩‍👦‍👦/PXL_20230815_160934535.jpg.json + 844 2024-05-25 22:15 Takeout/Google Photos/🇵🇹 Lisbonne ❤️ en famille 👨‍👩‍👦‍👦/PXL_20230815_161357571.jpg.json + 844 2024-05-25 22:15 Takeout/Google Photos/🇵🇹 Lisbonne ❤️ en famille 👨‍👩‍👦‍👦/PXL_20230815_160934535~2.jpg.json + 854 2024-05-25 22:15 Takeout/Google Photos/🇵🇹 Lisbonne ❤️ en famille 👨‍👩‍👦‍👦/PXL_20230815_170918725.jpg.json + 854 2024-05-25 22:15 Takeout/Google Photos/🇵🇹 Lisbonne ❤️ en famille 👨‍👩‍👦‍👦/PXL_20230815_170921221.jpg.json + 840 2024-05-25 22:15 Takeout/Google Photos/🇵🇹 Lisbonne ❤️ en famille 👨‍👩‍👦‍👦/PXL_20230815_172103511.jpg.json + 844 2024-05-25 22:15 Takeout/Google Photos/🇵🇹 Lisbonne ❤️ en famille 👨‍👩‍👦‍👦/PXL_20230815_184541352.jpg.json + 854 2024-05-25 22:15 Takeout/Google Photos/🇵🇹 Lisbonne ❤️ en famille 👨‍👩‍👦‍👦/PXL_20230815_171225430.jpg.json + 706 2024-05-25 22:15 Takeout/Google Photos/🇵🇹 Lisbonne ❤️ en famille 👨‍👩‍👦‍👦/IMG_1850.HEIC.json + 858 2024-05-25 22:15 Takeout/Google Photos/🇵🇹 Lisbonne ❤️ en famille 👨‍👩‍👦‍👦/PXL_20230815_191055522.jpg.json + 844 2024-05-25 22:15 Takeout/Google Photos/🇵🇹 Lisbonne ❤️ en famille 👨‍👩‍👦‍👦/PXL_20230815_184608476.jpg.json + 860 2024-05-25 22:15 Takeout/Google Photos/🇵🇹 Lisbonne ❤️ en famille 👨‍👩‍👦‍👦/PXL_20230815_191300435.jpg.json + 706 2024-05-25 22:15 Takeout/Google Photos/🇵🇹 Lisbonne ❤️ en famille 👨‍👩‍👦‍👦/IMG_1851.HEIC.json + 860 2024-05-25 22:15 Takeout/Google Photos/🇵🇹 Lisbonne ❤️ en famille 👨‍👩‍👦‍👦/PXL_20230815_193522767.jpg.json + 850 2024-05-25 22:15 Takeout/Google Photos/🇵🇹 Lisbonne ❤️ en famille 👨‍👩‍👦‍👦/PXL_20230815_201809279.NIGHT.jpg.json + 876 2024-05-25 22:15 Takeout/Google Photos/🇵🇹 Lisbonne ❤️ en famille 👨‍👩‍👦‍👦/PXL_20230815_202246258.jpg.json + 882 2024-05-25 22:15 Takeout/Google Photos/🇵🇹 Lisbonne ❤️ en famille 👨‍👩‍👦‍👦/PXL_20230815_202327379.NIGHT.jpg.json + 862 2024-05-25 22:15 Takeout/Google Photos/🇵🇹 Lisbonne ❤️ en famille 👨‍👩‍👦‍👦/PXL_20230815_201655580.NIGHT.jpg.json + 884 2024-05-25 22:15 Takeout/Google Photos/🇵🇹 Lisbonne ❤️ en famille 👨‍👩‍👦‍👦/PXL_20230815_202818387.NIGHT.jpg.json + 884 2024-05-25 22:15 Takeout/Google Photos/🇵🇹 Lisbonne ❤️ en famille 👨‍👩‍👦‍👦/PXL_20230815_202820142.NIGHT.jpg.json + 850 2024-05-25 22:15 Takeout/Google Photos/🇵🇹 Lisbonne ❤️ en famille 👨‍👩‍👦‍👦/PXL_20230816_065539076.NIGHT.jpg.json + 860 2024-05-25 22:15 Takeout/Google Photos/🇵🇹 Lisbonne ❤️ en famille 👨‍👩‍👦‍👦/PXL_20230816_060414573.jpg.json + 858 2024-05-25 22:15 Takeout/Google Photos/🇵🇹 Lisbonne ❤️ en famille 👨‍👩‍👦‍👦/PXL_20230816_071349105.jpg.json + 706 2024-05-25 22:15 Takeout/Google Photos/🇵🇹 Lisbonne ❤️ en famille 👨‍👩‍👦‍👦/IMG_1852.HEIC.json + 706 2024-05-25 22:15 Takeout/Google Photos/🇵🇹 Lisbonne ❤️ en famille 👨‍👩‍👦‍👦/IMG_1853.HEIC.json + 1186801 2024-05-25 22:15 Takeout/Google Photos/🇵🇹 Lisbonne ❤️ en famille 👨‍👩‍👦‍👦/IMG_1856.HEIC + 706 2024-05-25 22:15 Takeout/Google Photos/🇵🇹 Lisbonne ❤️ en famille 👨‍👩‍👦‍👦/IMG_1854.HEIC.json + 706 2024-05-25 22:15 Takeout/Google Photos/🇵🇹 Lisbonne ❤️ en famille 👨‍👩‍👦‍👦/IMG_1855.HEIC.json + 706 2024-05-25 22:15 Takeout/Google Photos/🇵🇹 Lisbonne ❤️ en famille 👨‍👩‍👦‍👦/IMG_1856.HEIC.json + 853 2024-05-25 22:15 Takeout/Google Photos/🇵🇹 Lisbonne ❤️ en famille 👨‍👩‍👦‍👦/PXL_20230816_113900491.LS.mp4.json + 706 2024-05-25 22:15 Takeout/Google Photos/🇵🇹 Lisbonne ❤️ en famille 👨‍👩‍👦‍👦/IMG_1857.HEIC.json + 846 2024-05-25 22:15 Takeout/Google Photos/🇵🇹 Lisbonne ❤️ en famille 👨‍👩‍👦‍👦/PXL_20230816_112210934.jpg.json + 862 2024-05-25 22:15 Takeout/Google Photos/🇵🇹 Lisbonne ❤️ en famille 👨‍👩‍👦‍👦/PXL_20230816_115318027.jpg.json + 706 2024-05-25 22:15 Takeout/Google Photos/🇵🇹 Lisbonne ❤️ en famille 👨‍👩‍👦‍👦/IMG_1859.HEIC.json + 123247 2024-05-25 22:15 Takeout/Google Photos/🇵🇹 Lisbonne ❤️ en famille 👨‍👩‍👦‍👦/IMG_1862.HEIC + 868 2024-05-25 22:15 Takeout/Google Photos/🇵🇹 Lisbonne ❤️ en famille 👨‍👩‍👦‍👦/PXL_20230816_132648337.NIGHT.jpg.json + 846 2024-05-25 22:15 Takeout/Google Photos/🇵🇹 Lisbonne ❤️ en famille 👨‍👩‍👦‍👦/PXL_20230816_143203982.jpg.json + 706 2024-05-25 22:15 Takeout/Google Photos/🇵🇹 Lisbonne ❤️ en famille 👨‍👩‍👦‍👦/IMG_1860.HEIC.json + 846 2024-05-25 22:15 Takeout/Google Photos/🇵🇹 Lisbonne ❤️ en famille 👨‍👩‍👦‍👦/PXL_20230816_143208443.jpg.json + 706 2024-05-25 22:15 Takeout/Google Photos/🇵🇹 Lisbonne ❤️ en famille 👨‍👩‍👦‍👦/IMG_1861.HEIC.json + 706 2024-05-25 22:15 Takeout/Google Photos/🇵🇹 Lisbonne ❤️ en famille 👨‍👩‍👦‍👦/IMG_1862.HEIC.json + 706 2024-05-25 22:15 Takeout/Google Photos/🇵🇹 Lisbonne ❤️ en famille 👨‍👩‍👦‍👦/IMG_1864.HEIC.json + 706 2024-05-25 22:15 Takeout/Google Photos/🇵🇹 Lisbonne ❤️ en famille 👨‍👩‍👦‍👦/IMG_1865.HEIC.json + 862 2024-05-25 22:15 Takeout/Google Photos/🇵🇹 Lisbonne ❤️ en famille 👨‍👩‍👦‍👦/PXL_20230816_191312144.jpg.json + 706 2024-05-25 22:15 Takeout/Google Photos/🇵🇹 Lisbonne ❤️ en famille 👨‍👩‍👦‍👦/IMG_1863.HEIC.json + 706 2024-05-25 22:15 Takeout/Google Photos/🇵🇹 Lisbonne ❤️ en famille 👨‍👩‍👦‍👦/IMG_1866.HEIC.json + 706 2024-05-25 22:15 Takeout/Google Photos/🇵🇹 Lisbonne ❤️ en famille 👨‍👩‍👦‍👦/IMG_1869.HEIC.json + 878 2024-05-25 22:15 Takeout/Google Photos/🇵🇹 Lisbonne ❤️ en famille 👨‍👩‍👦‍👦/PXL_20230816_211707485.jpg.json + 706 2024-05-25 22:15 Takeout/Google Photos/🇵🇹 Lisbonne ❤️ en famille 👨‍👩‍👦‍👦/IMG_1870.HEIC.json + 876 2024-05-25 22:15 Takeout/Google Photos/🇵🇹 Lisbonne ❤️ en famille 👨‍👩‍👦‍👦/PXL_20230816_202044782.jpg.json + 706 2024-05-25 22:15 Takeout/Google Photos/🇵🇹 Lisbonne ❤️ en famille 👨‍👩‍👦‍👦/IMG_1871.HEIC.json + 842 2024-05-25 22:15 Takeout/Google Photos/🇵🇹 Lisbonne ❤️ en famille 👨‍👩‍👦‍👦/PXL_20230817_071450157.jpg.json + 846 2024-05-25 22:15 Takeout/Google Photos/🇵🇹 Lisbonne ❤️ en famille 👨‍👩‍👦‍👦/PXL_20230817_072539487.jpg.json + 733 2024-05-25 22:15 Takeout/Google Photos/🇵🇹 Lisbonne ❤️ en famille 👨‍👩‍👦‍👦/FFE79A68-B0E6-472E-836D-EC49F351F588.jpg.json + 860 2024-05-25 22:15 Takeout/Google Photos/🇵🇹 Lisbonne ❤️ en famille 👨‍👩‍👦‍👦/PXL_20230817_080105375.jpg.json + 842 2024-05-25 22:15 Takeout/Google Photos/🇵🇹 Lisbonne ❤️ en famille 👨‍👩‍👦‍👦/PXL_20230817_081251352.jpg.json + 846 2024-05-25 22:15 Takeout/Google Photos/🇵🇹 Lisbonne ❤️ en famille 👨‍👩‍👦‍👦/PXL_20230817_121601920.jpg.json + 842 2024-05-25 22:15 Takeout/Google Photos/🇵🇹 Lisbonne ❤️ en famille 👨‍👩‍👦‍👦/PXL_20230817_075312564.jpg.json + 846 2024-05-25 22:15 Takeout/Google Photos/🇵🇹 Lisbonne ❤️ en famille 👨‍👩‍👦‍👦/PXL_20230817_131815116.jpg.json + 706 2024-05-25 22:15 Takeout/Google Photos/🇵🇹 Lisbonne ❤️ en famille 👨‍👩‍👦‍👦/IMG_1875.HEIC.json + 706 2024-05-25 22:15 Takeout/Google Photos/🇵🇹 Lisbonne ❤️ en famille 👨‍👩‍👦‍👦/IMG_1876.HEIC.json + 846 2024-05-25 22:15 Takeout/Google Photos/🇵🇹 Lisbonne ❤️ en famille 👨‍👩‍👦‍👦/PXL_20230817_170752393.jpg.json + 860 2024-05-25 22:15 Takeout/Google Photos/🇵🇹 Lisbonne ❤️ en famille 👨‍👩‍👦‍👦/PXL_20230817_181209268.jpg.json + 706 2024-05-25 22:15 Takeout/Google Photos/🇵🇹 Lisbonne ❤️ en famille 👨‍👩‍👦‍👦/IMG_1877.HEIC.json + 845 2024-05-25 22:15 Takeout/Google Photos/🇵🇹 Lisbonne ❤️ en famille 👨‍👩‍👦‍👦/PXL_20230817_175514506.PANO.jpg.json + 858 2024-05-25 22:15 Takeout/Google Photos/🇵🇹 Lisbonne ❤️ en famille 👨‍👩‍👦‍👦/PXL_20230817_181502346.jpg.json + 858 2024-05-25 22:15 Takeout/Google Photos/🇵🇹 Lisbonne ❤️ en famille 👨‍👩‍👦‍👦/PXL_20230817_181456746.jpg.json + 844 2024-05-25 22:15 Takeout/Google Photos/🇵🇹 Lisbonne ❤️ en famille 👨‍👩‍👦‍👦/PXL_20230817_183021857.jpg.json + 842 2024-05-25 22:15 Takeout/Google Photos/🇵🇹 Lisbonne ❤️ en famille 👨‍👩‍👦‍👦/PXL_20230817_183618613.jpg.json + 831 2024-05-25 22:15 Takeout/Google Photos/🇵🇹 Lisbonne ❤️ en famille 👨‍👩‍👦‍👦/PXL_20230817_183716695.LS.mp4.json + 860 2024-05-25 22:15 Takeout/Google Photos/🇵🇹 Lisbonne ❤️ en famille 👨‍👩‍👦‍👦/PXL_20230817_183751525.jpg.json + 860 2024-05-25 22:15 Takeout/Google Photos/🇵🇹 Lisbonne ❤️ en famille 👨‍👩‍👦‍👦/PXL_20230817_183811061.jpg.json + 860 2024-05-25 22:15 Takeout/Google Photos/🇵🇹 Lisbonne ❤️ en famille 👨‍👩‍👦‍👦/PXL_20230817_183801046.jpg.json + 860 2024-05-25 22:15 Takeout/Google Photos/🇵🇹 Lisbonne ❤️ en famille 👨‍👩‍👦‍👦/PXL_20230817_183826357.jpg.json + 706 2024-05-25 22:15 Takeout/Google Photos/🇵🇹 Lisbonne ❤️ en famille 👨‍👩‍👦‍👦/IMG_1773.HEIC.json + 733 2024-05-25 22:15 Takeout/Google Photos/🇵🇹 Lisbonne ❤️ en famille 👨‍👩‍👦‍👦/509C843D-D4B9-4F02-81B0-05BE938F12DF.jpg.json + 706 2024-05-25 22:15 Takeout/Google Photos/🇵🇹 Lisbonne ❤️ en famille 👨‍👩‍👦‍👦/IMG_1878.HEIC.json + 856 2024-05-25 22:15 Takeout/Google Photos/🇵🇹 Lisbonne ❤️ en famille 👨‍👩‍👦‍👦/PXL_20230817_193237877.jpg.json + 844 2024-05-25 22:15 Takeout/Google Photos/🇵🇹 Lisbonne ❤️ en famille 👨‍👩‍👦‍👦/PXL_20230817_194439146.jpg.json + 853 2024-05-25 22:15 Takeout/Google Photos/🇵🇹 Lisbonne ❤️ en famille 👨‍👩‍👦‍👦/PXL_20230817_195943901.LS.mp4.json + 876 2024-05-25 22:15 Takeout/Google Photos/🇵🇹 Lisbonne ❤️ en famille 👨‍👩‍👦‍👦/PXL_20230817_200858587.jpg.json + 876 2024-05-25 22:15 Takeout/Google Photos/🇵🇹 Lisbonne ❤️ en famille 👨‍👩‍👦‍👦/PXL_20230817_200900799.jpg.json + 860 2024-05-25 22:15 Takeout/Google Photos/🇵🇹 Lisbonne ❤️ en famille 👨‍👩‍👦‍👦/PXL_20230817_201212577.jpg.json + 848 2024-05-25 22:15 Takeout/Google Photos/🇵🇹 Lisbonne ❤️ en famille 👨‍👩‍👦‍👦/PXL_20230817_202545906.NIGHT.jpg.json + 848 2024-05-25 22:15 Takeout/Google Photos/🇵🇹 Lisbonne ❤️ en famille 👨‍👩‍👦‍👦/PXL_20230817_202555916.NIGHT.jpg.json + 842 2024-05-25 22:15 Takeout/Google Photos/🇵🇹 Lisbonne ❤️ en famille 👨‍👩‍👦‍👦/PXL_20230813_085220659.jpg.json + 829 2024-05-25 22:15 Takeout/Google Photos/🇵🇹 Lisbonne ❤️ en famille 👨‍👩‍👦‍👦/PXL_20230817_202746758.LS.mp4.json + 844 2024-05-25 22:15 Takeout/Google Photos/🇵🇹 Lisbonne ❤️ en famille 👨‍👩‍👦‍👦/PXL_20230818_062827230.jpg.json + 842 2024-05-25 22:15 Takeout/Google Photos/🇵🇹 Lisbonne ❤️ en famille 👨‍👩‍👦‍👦/PXL_20230818_072713034.jpg.json + 842 2024-05-25 22:15 Takeout/Google Photos/🇵🇹 Lisbonne ❤️ en famille 👨‍👩‍👦‍👦/PXL_20230818_072728336.jpg.json + 862 2024-05-25 22:15 Takeout/Google Photos/🇵🇹 Lisbonne ❤️ en famille 👨‍👩‍👦‍👦/PXL_20230818_073034374.jpg.json + 845 2024-05-25 22:15 Takeout/Google Photos/🇵🇹 Lisbonne ❤️ en famille 👨‍👩‍👦‍👦/PXL_20230818_073228970.PANO.jpg.json + 831 2024-05-25 22:15 Takeout/Google Photos/🇵🇹 Lisbonne ❤️ en famille 👨‍👩‍👦‍👦/PXL_20230818_073402211.TS.mp4.json + 862 2024-05-25 22:15 Takeout/Google Photos/🇵🇹 Lisbonne ❤️ en famille 👨‍👩‍👦‍👦/PXL_20230818_073704846.jpg.json + 862 2024-05-25 22:15 Takeout/Google Photos/🇵🇹 Lisbonne ❤️ en famille 👨‍👩‍👦‍👦/PXL_20230818_073846874.jpg.json + 862 2024-05-25 22:15 Takeout/Google Photos/🇵🇹 Lisbonne ❤️ en famille 👨‍👩‍👦‍👦/PXL_20230818_074307497.jpg.json + 844 2024-05-25 22:15 Takeout/Google Photos/🇵🇹 Lisbonne ❤️ en famille 👨‍👩‍👦‍👦/PXL_20230818_080921955.jpg.json + 844 2024-05-25 22:15 Takeout/Google Photos/🇵🇹 Lisbonne ❤️ en famille 👨‍👩‍👦‍👦/PXL_20230818_080922936.jpg.json + 858 2024-05-25 22:15 Takeout/Google Photos/🇵🇹 Lisbonne ❤️ en famille 👨‍👩‍👦‍👦/PXL_20230818_080937939.jpg.json + 858 2024-05-25 22:15 Takeout/Google Photos/🇵🇹 Lisbonne ❤️ en famille 👨‍👩‍👦‍👦/PXL_20230818_081231702.jpg.json + 862 2024-05-25 22:15 Takeout/Google Photos/🇵🇹 Lisbonne ❤️ en famille 👨‍👩‍👦‍👦/PXL_20230818_082348579.jpg.json + 844 2024-05-25 22:15 Takeout/Google Photos/🇵🇹 Lisbonne ❤️ en famille 👨‍👩‍👦‍👦/PXL_20230818_082351912.jpg.json + 862 2024-05-25 22:15 Takeout/Google Photos/🇵🇹 Lisbonne ❤️ en famille 👨‍👩‍👦‍👦/PXL_20230818_130000489.jpg.json + 844 2024-05-25 22:15 Takeout/Google Photos/🇵🇹 Lisbonne ❤️ en famille 👨‍👩‍👦‍👦/PXL_20230818_132150855.jpg.json + 862 2024-05-25 22:15 Takeout/Google Photos/🇵🇹 Lisbonne ❤️ en famille 👨‍👩‍👦‍👦/PXL_20230818_144557167.jpg.json + 295 2018-07-21 09:08 Takeout/Google Photos/Garros 19 Juillet 2018/métadonnées.json + 860 2024-05-25 22:15 Takeout/Google Photos/🇵🇹 Lisbonne ❤️ en famille 👨‍👩‍👦‍👦/PXL_20230818_134521846.jpg.json + 878 2024-05-25 22:15 Takeout/Google Photos/🇵🇹 Lisbonne ❤️ en famille 👨‍👩‍👦‍👦/PXL_20230818_144231600.jpg.json + 862 2024-05-25 22:15 Takeout/Google Photos/🇵🇹 Lisbonne ❤️ en famille 👨‍👩‍👦‍👦/PXL_20230818_144716103.jpg.json + 846 2024-05-25 22:15 Takeout/Google Photos/🇵🇹 Lisbonne ❤️ en famille 👨‍👩‍👦‍👦/PXL_20230818_150420324.jpg.json + 720710 2024-05-25 22:15 Takeout/Google Photos/Garros 19 Juillet 2018/IMG_20180719_191506.jpg + 789 2024-05-25 22:15 Takeout/Google Photos/Garros 19 Juillet 2018/Bebop2_20180719182934+0200.mp4.json + 812 2024-05-25 22:15 Takeout/Google Photos/🇵🇹 Lisbonne ❤️ en famille 👨‍👩‍👦‍👦/PXL_20230818_161304257.jpg.json + 407330 2024-05-25 22:15 Takeout/Google Photos/Garros 19 Juillet 2018/IMG_8151.JPG + 785 2024-05-25 22:15 Takeout/Google Photos/Garros 19 Juillet 2018/Bebop2_20180719183450+0200.mp4.json + 763 2024-05-25 22:15 Takeout/Google Photos/Garros 19 Juillet 2018/Bebop2_20180719185209+0200.mp4.json + 369458 2024-05-25 22:15 Takeout/Google Photos/Garros 19 Juillet 2018/IMG_8153.JPG + 763 2024-05-25 22:15 Takeout/Google Photos/Garros 19 Juillet 2018/Bebop2_20180719185840+0200.mp4.json + 731 2024-05-25 22:15 Takeout/Google Photos/Garros 19 Juillet 2018/IMG_8152.JPG.json + 810 2024-05-25 22:15 Takeout/Google Photos/Garros 19 Juillet 2018/IMG_20180719_191506.jpg.json + 854 2024-05-25 22:15 Takeout/Google Photos/Garros 19 Juillet 2018/IMG_20180719_191638.jpg.json + 731 2024-05-25 22:15 Takeout/Google Photos/Garros 19 Juillet 2018/IMG_8151.JPG.json + 731 2024-05-25 22:15 Takeout/Google Photos/Garros 19 Juillet 2018/IMG_8153.JPG.json + 763 2024-05-25 22:15 Takeout/Google Photos/Garros 19 Juillet 2018/Bebop2_20180719194940+0200.mp4.json + 731 2024-05-25 22:15 Takeout/Google Photos/Garros 19 Juillet 2018/IMG_8155.JPG.json + 731 2024-05-25 22:15 Takeout/Google Photos/Garros 19 Juillet 2018/IMG_8156.JPG.json + 731 2024-05-25 22:15 Takeout/Google Photos/Garros 19 Juillet 2018/IMG_8157.JPG.json + 731 2024-05-25 22:15 Takeout/Google Photos/Garros 19 Juillet 2018/IMG_8158.JPG.json + 810 2024-05-25 22:15 Takeout/Google Photos/Garros 19 Juillet 2018/IMG_20180719_200157.jpg.json + 731 2024-05-25 22:15 Takeout/Google Photos/Garros 19 Juillet 2018/IMG_8162.JPG.json + 731 2024-05-25 22:15 Takeout/Google Photos/Garros 19 Juillet 2018/IMG_8163.JPG.json + 731 2024-05-25 22:15 Takeout/Google Photos/Garros 19 Juillet 2018/IMG_8164.JPG.json + 731 2024-05-25 22:15 Takeout/Google Photos/Garros 19 Juillet 2018/IMG_8165.JPG.json + 731 2024-05-25 22:15 Takeout/Google Photos/Garros 19 Juillet 2018/IMG_8166.JPG.json + 731 2024-05-25 22:15 Takeout/Google Photos/Garros 19 Juillet 2018/IMG_8167.JPG.json + 763 2024-05-25 22:15 Takeout/Google Photos/Garros 19 Juillet 2018/Bebop2_20180719201922+0200.mp4.json + 731 2024-05-25 22:15 Takeout/Google Photos/Garros 19 Juillet 2018/IMG_8168.JPG.json + 731 2024-05-25 22:15 Takeout/Google Photos/Garros 19 Juillet 2018/IMG_8169.JPG.json + 731 2024-05-25 22:15 Takeout/Google Photos/Garros 19 Juillet 2018/IMG_8172.JPG.json + 731 2024-05-25 22:15 Takeout/Google Photos/Garros 19 Juillet 2018/IMG_8170.JPG.json + 763 2024-05-25 22:15 Takeout/Google Photos/Garros 19 Juillet 2018/Bebop2_20180719203057+0200.mp4.json + 731 2024-05-25 22:15 Takeout/Google Photos/Garros 19 Juillet 2018/IMG_8177.JPG.json + 731 2024-05-25 22:15 Takeout/Google Photos/Garros 19 Juillet 2018/IMG_8178.JPG.json + 731 2024-05-25 22:15 Takeout/Google Photos/Garros 19 Juillet 2018/IMG_8179.JPG.json + 731 2024-05-25 22:15 Takeout/Google Photos/Garros 19 Juillet 2018/IMG_8181.JPG.json + 763 2024-05-25 22:15 Takeout/Google Photos/Garros 19 Juillet 2018/Bebop2_20180719211425+0200.mp4.json + 806 2024-05-25 22:15 Takeout/Google Photos/Garros 19 Juillet 2018/Bebop2_20180719211742+0200.jpg.json + 336456 2024-05-25 22:15 Takeout/archive_browser.html +--------- ------- +1070219299 807 files +takeout-20240525T201456Z-002.zip: +Archive: takeout-20240525T201456Z-002.zip + Length Date Time Name +--------- ---------- ----- ---- + 2730889 2024-05-25 22:15 Takeout/Google Photos/🇵🇹 Lisbonne ❤️ en famille 👨‍👩‍👦‍👦/PXL_20230815_152303067.jpg + 5363355 2024-05-25 22:15 Takeout/Google Photos/🇵🇹 Lisbonne ❤️ en famille 👨‍👩‍👦‍👦/PXL_20230815_132231336.jpg + 2422683 2024-05-25 22:15 Takeout/Google Photos/🇵🇹 Lisbonne ❤️ en famille 👨‍👩‍👦‍👦/PXL_20230815_153003181~3.jpg + 4243153 2024-05-25 22:15 Takeout/Google Photos/🇵🇹 Lisbonne ❤️ en famille 👨‍👩‍👦‍👦/PXL_20230815_132154767.jpg + 2531099 2024-05-25 22:15 Takeout/Google Photos/🇵🇹 Lisbonne ❤️ en famille 👨‍👩‍👦‍👦/PXL_20230815_152846037.jpg + 2085622 2024-05-25 22:15 Takeout/Google Photos/🇵🇹 Lisbonne ❤️ en famille 👨‍👩‍👦‍👦/PXL_20230815_131100760.jpg + 2553353 2024-05-25 22:15 Takeout/Google Photos/🇵🇹 Lisbonne ❤️ en famille 👨‍👩‍👦‍👦/PXL_20230815_152841555.jpg + 2919006 2024-05-25 22:15 Takeout/Google Photos/🇵🇹 Lisbonne ❤️ en famille 👨‍👩‍👦‍👦/PXL_20230815_153003181.jpg + 2148816 2024-05-25 22:15 Takeout/Google Photos/🇵🇹 Lisbonne ❤️ en famille 👨‍👩‍👦‍👦/PXL_20230815_152846037~2.jpg + 2936280 2024-05-25 22:15 Takeout/Google Photos/🇵🇹 Lisbonne ❤️ en famille 👨‍👩‍👦‍👦/PXL_20230815_152254524.jpg + 2422348 2024-05-25 22:15 Takeout/Google Photos/🇵🇹 Lisbonne ❤️ en famille 👨‍👩‍👦‍👦/PXL_20230815_153003181~2.jpg + 3301585 2024-05-25 22:15 Takeout/Google Photos/🇵🇹 Lisbonne ❤️ en famille 👨‍👩‍👦‍👦/PXL_20230815_153110793.jpg + 1781697 2024-05-25 22:15 Takeout/Google Photos/🇵🇹 Lisbonne ❤️ en famille 👨‍👩‍👦‍👦/PXL_20230815_125637640.jpg + 2917045 2024-05-25 22:15 Takeout/Google Photos/🇵🇹 Lisbonne ❤️ en famille 👨‍👩‍👦‍👦/PXL_20230815_152405874.jpg + 2865401 2024-05-25 22:15 Takeout/Google Photos/🇵🇹 Lisbonne ❤️ en famille 👨‍👩‍👦‍👦/IMG_1849.HEIC + 7552407 2024-05-25 22:15 Takeout/Google Photos/🇵🇹 Lisbonne ❤️ en famille 👨‍👩‍👦‍👦/PXL_20230815_150752249.PANO.jpg + 4061761 2024-05-25 22:15 Takeout/Google Photos/🇵🇹 Lisbonne ❤️ en famille 👨‍👩‍👦‍👦/PXL_20230815_153603660.jpg + 3637703 2024-05-25 22:15 Takeout/Google Photos/🇵🇹 Lisbonne ❤️ en famille 👨‍👩‍👦‍👦/PXL_20230815_153308948.jpg + 3337879 2024-05-25 22:15 Takeout/Google Photos/🇵🇹 Lisbonne ❤️ en famille 👨‍👩‍👦‍👦/PXL_20230815_155435571.jpg + 4970836 2024-05-25 22:15 Takeout/Google Photos/🇵🇹 Lisbonne ❤️ en famille 👨‍👩‍👦‍👦/PXL_20230815_151238032.jpg + 3267844 2024-05-25 22:15 Takeout/Google Photos/🇵🇹 Lisbonne ❤️ en famille 👨‍👩‍👦‍👦/PXL_20230815_153359013.jpg + 2905051 2024-05-25 22:15 Takeout/Google Photos/🇵🇹 Lisbonne ❤️ en famille 👨‍👩‍👦‍👦/PXL_20230815_160052888.jpg + 3833491 2024-05-25 22:15 Takeout/Google Photos/🇵🇹 Lisbonne ❤️ en famille 👨‍👩‍👦‍👦/IMG_1850.HEIC + 2315157 2024-05-25 22:15 Takeout/Google Photos/🇵🇹 Lisbonne ❤️ en famille 👨‍👩‍👦‍👦/PXL_20230815_155505084.jpg + 1810781 2024-05-25 22:15 Takeout/Google Photos/🇵🇹 Lisbonne ❤️ en famille 👨‍👩‍👦‍👦/PXL_20230815_171225430.jpg + 3089972 2024-05-25 22:15 Takeout/Google Photos/🇵🇹 Lisbonne ❤️ en famille 👨‍👩‍👦‍👦/PXL_20230815_160105481.jpg + 2991863 2024-05-25 22:15 Takeout/Google Photos/🇵🇹 Lisbonne ❤️ en famille 👨‍👩‍👦‍👦/PXL_20230815_160934535~2.jpg + 2795499 2024-05-25 22:15 Takeout/Google Photos/🇵🇹 Lisbonne ❤️ en famille 👨‍👩‍👦‍👦/PXL_20230815_160831688.jpg + 1797635 2024-05-25 22:15 Takeout/Google Photos/🇵🇹 Lisbonne ❤️ en famille 👨‍👩‍👦‍👦/PXL_20230815_170921221.jpg + 3035389 2024-05-25 22:15 Takeout/Google Photos/🇵🇹 Lisbonne ❤️ en famille 👨‍👩‍👦‍👦/IMG_1851.HEIC + 2110158 2024-05-25 22:15 Takeout/Google Photos/🇵🇹 Lisbonne ❤️ en famille 👨‍👩‍👦‍👦/PXL_20230815_170918725.jpg + 4455300 2024-05-25 22:15 Takeout/Google Photos/🇵🇹 Lisbonne ❤️ en famille 👨‍👩‍👦‍👦/PXL_20230815_125540275.TS.mp4 + 3174153 2024-05-25 22:15 Takeout/Google Photos/🇵🇹 Lisbonne ❤️ en famille 👨‍👩‍👦‍👦/PXL_20230815_161357571.jpg + 3529803 2024-05-25 22:15 Takeout/Google Photos/🇵🇹 Lisbonne ❤️ en famille 👨‍👩‍👦‍👦/PXL_20230815_160934535.jpg + 3058540 2024-05-25 22:15 Takeout/Google Photos/🇵🇹 Lisbonne ❤️ en famille 👨‍👩‍👦‍👦/PXL_20230815_172103511.jpg + 2205991 2024-05-25 22:15 Takeout/Google Photos/🇵🇹 Lisbonne ❤️ en famille 👨‍👩‍👦‍👦/PXL_20230815_191300435.jpg + 1808446 2024-05-25 22:15 Takeout/Google Photos/🇵🇹 Lisbonne ❤️ en famille 👨‍👩‍👦‍👦/IMG_1854.HEIC + 2152786 2024-05-25 22:15 Takeout/Google Photos/🇵🇹 Lisbonne ❤️ en famille 👨‍👩‍👦‍👦/IMG_1852.HEIC + 2078603 2024-05-25 22:15 Takeout/Google Photos/🇵🇹 Lisbonne ❤️ en famille 👨‍👩‍👦‍👦/PXL_20230815_201655580.NIGHT.jpg + 2460454 2024-05-25 22:15 Takeout/Google Photos/🇵🇹 Lisbonne ❤️ en famille 👨‍👩‍👦‍👦/PXL_20230815_191055522.jpg + 1695246 2024-05-25 22:15 Takeout/Google Photos/🇵🇹 Lisbonne ❤️ en famille 👨‍👩‍👦‍👦/IMG_1855.HEIC + 2452610 2024-05-25 22:15 Takeout/Google Photos/🇵🇹 Lisbonne ❤️ en famille 👨‍👩‍👦‍👦/PXL_20230815_184608476.jpg + 1514652 2024-05-25 22:15 Takeout/Google Photos/🇵🇹 Lisbonne ❤️ en famille 👨‍👩‍👦‍👦/PXL_20230816_065539076.NIGHT.jpg + 2019308 2024-05-25 22:15 Takeout/Google Photos/🇵🇹 Lisbonne ❤️ en famille 👨‍👩‍👦‍👦/PXL_20230815_202818387.NIGHT.jpg + 4238096 2024-05-25 22:15 Takeout/Google Photos/🇵🇹 Lisbonne ❤️ en famille 👨‍👩‍👦‍👦/PXL_20230815_184541352.jpg + 2467619 2024-05-25 22:15 Takeout/Google Photos/🇵🇹 Lisbonne ❤️ en famille 👨‍👩‍👦‍👦/IMG_1857.HEIC + 1836534 2024-05-25 22:15 Takeout/Google Photos/🇵🇹 Lisbonne ❤️ en famille 👨‍👩‍👦‍👦/IMG_1853.HEIC + 1971312 2024-05-25 22:15 Takeout/Google Photos/🇵🇹 Lisbonne ❤️ en famille 👨‍👩‍👦‍👦/PXL_20230815_202820142.NIGHT.jpg + 2553153 2024-05-25 22:15 Takeout/Google Photos/🇵🇹 Lisbonne ❤️ en famille 👨‍👩‍👦‍👦/PXL_20230815_202327379.NIGHT.jpg + 2015307 2024-05-25 22:15 Takeout/Google Photos/🇵🇹 Lisbonne ❤️ en famille 👨‍👩‍👦‍👦/PXL_20230816_060414573.jpg + 3543300 2024-05-25 22:15 Takeout/Google Photos/🇵🇹 Lisbonne ❤️ en famille 👨‍👩‍👦‍👦/PXL_20230815_193522767.jpg + 2084436 2024-05-25 22:15 Takeout/Google Photos/🇵🇹 Lisbonne ❤️ en famille 👨‍👩‍👦‍👦/PXL_20230815_201809279.NIGHT.jpg + 2875776 2024-05-25 22:15 Takeout/Google Photos/🇵🇹 Lisbonne ❤️ en famille 👨‍👩‍👦‍👦/PXL_20230815_202246258.jpg + 1593944 2024-05-25 22:15 Takeout/Google Photos/🇵🇹 Lisbonne ❤️ en famille 👨‍👩‍👦‍👦/IMG_1859.HEIC + 1587732 2024-05-25 22:15 Takeout/Google Photos/🇵🇹 Lisbonne ❤️ en famille 👨‍👩‍👦‍👦/PXL_20230816_112210934.jpg + 1669594 2024-05-25 22:15 Takeout/Google Photos/🇵🇹 Lisbonne ❤️ en famille 👨‍👩‍👦‍👦/IMG_1860.HEIC + 2611926 2024-05-25 22:15 Takeout/Google Photos/🇵🇹 Lisbonne ❤️ en famille 👨‍👩‍👦‍👦/IMG_1864.HEIC + 3620068 2024-05-25 22:15 Takeout/Google Photos/🇵🇹 Lisbonne ❤️ en famille 👨‍👩‍👦‍👦/IMG_1865.HEIC + 2891650 2024-05-25 22:15 Takeout/Google Photos/🇵🇹 Lisbonne ❤️ en famille 👨‍👩‍👦‍👦/IMG_1861.HEIC + 1763765 2024-05-25 22:15 Takeout/Google Photos/🇵🇹 Lisbonne ❤️ en famille 👨‍👩‍👦‍👦/PXL_20230816_143203982.jpg + 1172303 2024-05-25 22:15 Takeout/Google Photos/🇵🇹 Lisbonne ❤️ en famille 👨‍👩‍👦‍👦/IMG_1870.HEIC + 1703266 2024-05-25 22:15 Takeout/Google Photos/🇵🇹 Lisbonne ❤️ en famille 👨‍👩‍👦‍👦/IMG_1863.HEIC + 1993207 2024-05-25 22:15 Takeout/Google Photos/🇵🇹 Lisbonne ❤️ en famille 👨‍👩‍👦‍👦/PXL_20230816_115318027.jpg + 2813596 2024-05-25 22:15 Takeout/Google Photos/🇵🇹 Lisbonne ❤️ en famille 👨‍👩‍👦‍👦/PXL_20230816_071349105.jpg + 1023438 2024-05-25 22:15 Takeout/Google Photos/🇵🇹 Lisbonne ❤️ en famille 👨‍👩‍👦‍👦/PXL_20230816_113900491.LS.mp4 + 504153 2024-05-25 22:15 Takeout/Google Photos/🇵🇹 Lisbonne ❤️ en famille 👨‍👩‍👦‍👦/IMG_1871.HEIC + 2609777 2024-05-25 22:15 Takeout/Google Photos/🇵🇹 Lisbonne ❤️ en famille 👨‍👩‍👦‍👦/IMG_1866.HEIC + 1928320 2024-05-25 22:15 Takeout/Google Photos/🇵🇹 Lisbonne ❤️ en famille 👨‍👩‍👦‍👦/PXL_20230816_132648337.NIGHT.jpg + 1679572 2024-05-25 22:15 Takeout/Google Photos/🇵🇹 Lisbonne ❤️ en famille 👨‍👩‍👦‍👦/PXL_20230816_143208443.jpg + 2154644 2024-05-25 22:15 Takeout/Google Photos/🇵🇹 Lisbonne ❤️ en famille 👨‍👩‍👦‍👦/IMG_1869.HEIC + 1382021 2024-05-25 22:15 Takeout/Google Photos/🇵🇹 Lisbonne ❤️ en famille 👨‍👩‍👦‍👦/FFE79A68-B0E6-472E-836D-EC49F351F588.jpg + 942104 2024-05-25 22:15 Takeout/Google Photos/🇵🇹 Lisbonne ❤️ en famille 👨‍👩‍👦‍👦/IMG_1875.HEIC + 1097934 2024-05-25 22:15 Takeout/Google Photos/🇵🇹 Lisbonne ❤️ en famille 👨‍👩‍👦‍👦/IMG_1876.HEIC + 3537613 2024-05-25 22:15 Takeout/Google Photos/🇵🇹 Lisbonne ❤️ en famille 👨‍👩‍👦‍👦/PXL_20230816_191312144.jpg + 2723602 2024-05-25 22:15 Takeout/Google Photos/🇵🇹 Lisbonne ❤️ en famille 👨‍👩‍👦‍👦/PXL_20230817_080105375.jpg + 3517863 2024-05-25 22:15 Takeout/Google Photos/🇵🇹 Lisbonne ❤️ en famille 👨‍👩‍👦‍👦/IMG_1877.HEIC + 2905752 2024-05-25 22:15 Takeout/Google Photos/🇵🇹 Lisbonne ❤️ en famille 👨‍👩‍👦‍👦/PXL_20230816_202044782.jpg + 3391315 2024-05-25 22:15 Takeout/Google Photos/🇵🇹 Lisbonne ❤️ en famille 👨‍👩‍👦‍👦/PXL_20230817_075312564.jpg + 2220923 2024-05-25 22:15 Takeout/Google Photos/🇵🇹 Lisbonne ❤️ en famille 👨‍👩‍👦‍👦/PXL_20230817_131815116.jpg + 2520832 2024-05-25 22:15 Takeout/Google Photos/🇵🇹 Lisbonne ❤️ en famille 👨‍👩‍👦‍👦/PXL_20230816_211707485.jpg + 2378485 2024-05-25 22:15 Takeout/Google Photos/🇵🇹 Lisbonne ❤️ en famille 👨‍👩‍👦‍👦/PXL_20230817_071450157.jpg + 3485518 2024-05-25 22:15 Takeout/Google Photos/🇵🇹 Lisbonne ❤️ en famille 👨‍👩‍👦‍👦/PXL_20230817_121601920.jpg + 3695668 2024-05-25 22:15 Takeout/Google Photos/🇵🇹 Lisbonne ❤️ en famille 👨‍👩‍👦‍👦/PXL_20230817_072539487.jpg + 3414098 2024-05-25 22:15 Takeout/Google Photos/🇵🇹 Lisbonne ❤️ en famille 👨‍👩‍👦‍👦/PXL_20230817_175514506.PANO.jpg + 3322147 2024-05-25 22:15 Takeout/Google Photos/🇵🇹 Lisbonne ❤️ en famille 👨‍👩‍👦‍👦/PXL_20230817_081251352.jpg + 2424218 2024-05-25 22:15 Takeout/Google Photos/🇵🇹 Lisbonne ❤️ en famille 👨‍👩‍👦‍👦/IMG_1878.HEIC + 2410890 2024-05-25 22:15 Takeout/Google Photos/🇵🇹 Lisbonne ❤️ en famille 👨‍👩‍👦‍👦/PXL_20230817_181502346.jpg + 2330097 2024-05-25 22:15 Takeout/Google Photos/🇵🇹 Lisbonne ❤️ en famille 👨‍👩‍👦‍👦/PXL_20230817_183801046.jpg + 3377082 2024-05-25 22:15 Takeout/Google Photos/🇵🇹 Lisbonne ❤️ en famille 👨‍👩‍👦‍👦/PXL_20230817_183618613.jpg + 2557888 2024-05-25 22:15 Takeout/Google Photos/🇵🇹 Lisbonne ❤️ en famille 👨‍👩‍👦‍👦/PXL_20230817_181209268.jpg + 2630534 2024-05-25 22:15 Takeout/Google Photos/🇵🇹 Lisbonne ❤️ en famille 👨‍👩‍👦‍👦/PXL_20230817_183021857.jpg + 2496726 2024-05-25 22:15 Takeout/Google Photos/🇵🇹 Lisbonne ❤️ en famille 👨‍👩‍👦‍👦/PXL_20230817_183826357.jpg + 2413675 2024-05-25 22:15 Takeout/Google Photos/🇵🇹 Lisbonne ❤️ en famille 👨‍👩‍👦‍👦/PXL_20230817_181456746.jpg + 2214172 2024-05-25 22:15 Takeout/Google Photos/🇵🇹 Lisbonne ❤️ en famille 👨‍👩‍👦‍👦/509C843D-D4B9-4F02-81B0-05BE938F12DF.jpg + 1985323 2024-05-25 22:15 Takeout/Google Photos/🇵🇹 Lisbonne ❤️ en famille 👨‍👩‍👦‍👦/PXL_20230817_183811061.jpg + 2071081 2024-05-25 22:15 Takeout/Google Photos/🇵🇹 Lisbonne ❤️ en famille 👨‍👩‍👦‍👦/PXL_20230817_194439146.jpg + 1875898 2024-05-25 22:15 Takeout/Google Photos/🇵🇹 Lisbonne ❤️ en famille 👨‍👩‍👦‍👦/PXL_20230817_200900799.jpg + 5670281 2024-05-25 22:15 Takeout/Google Photos/🇵🇹 Lisbonne ❤️ en famille 👨‍👩‍👦‍👦/PXL_20230817_170752393.jpg + 2963787 2024-05-25 22:15 Takeout/Google Photos/🇵🇹 Lisbonne ❤️ en famille 👨‍👩‍👦‍👦/PXL_20230817_183751525.jpg + 2108272 2024-05-25 22:15 Takeout/Google Photos/🇵🇹 Lisbonne ❤️ en famille 👨‍👩‍👦‍👦/PXL_20230817_183716695.LS.mp4 + 2131124 2024-05-25 22:15 Takeout/Google Photos/🇵🇹 Lisbonne ❤️ en famille 👨‍👩‍👦‍👦/PXL_20230817_202545906.NIGHT.jpg + 3579884 2024-05-25 22:15 Takeout/Google Photos/🇵🇹 Lisbonne ❤️ en famille 👨‍👩‍👦‍👦/PXL_20230817_193237877.jpg + 2963124 2024-05-25 22:15 Takeout/Google Photos/🇵🇹 Lisbonne ❤️ en famille 👨‍👩‍👦‍👦/PXL_20230817_200858587.jpg + 1964148 2024-05-25 22:15 Takeout/Google Photos/🇵🇹 Lisbonne ❤️ en famille 👨‍👩‍👦‍👦/PXL_20230818_072713034.jpg + 1902861 2024-05-25 22:15 Takeout/Google Photos/🇵🇹 Lisbonne ❤️ en famille 👨‍👩‍👦‍👦/PXL_20230817_202555916.NIGHT.jpg + 1468513 2024-05-25 22:15 Takeout/Google Photos/🇵🇹 Lisbonne ❤️ en famille 👨‍👩‍👦‍👦/PXL_20230817_201212577.jpg + 1959607 2024-05-25 22:15 Takeout/Google Photos/🇵🇹 Lisbonne ❤️ en famille 👨‍👩‍👦‍👦/PXL_20230818_062827230.jpg + 2666859 2024-05-25 22:15 Takeout/Google Photos/🇵🇹 Lisbonne ❤️ en famille 👨‍👩‍👦‍👦/PXL_20230817_195943901.LS.mp4 + 1757662 2024-05-25 22:15 Takeout/Google Photos/🇵🇹 Lisbonne ❤️ en famille 👨‍👩‍👦‍👦/PXL_20230818_080922936.jpg + 1661260 2024-05-25 22:15 Takeout/Google Photos/🇵🇹 Lisbonne ❤️ en famille 👨‍👩‍👦‍👦/PXL_20230818_080937939.jpg + 3945089 2024-05-25 22:15 Takeout/Google Photos/🇵🇹 Lisbonne ❤️ en famille 👨‍👩‍👦‍👦/PXL_20230818_073228970.PANO.jpg + 2307315 2024-05-25 22:15 Takeout/Google Photos/🇵🇹 Lisbonne ❤️ en famille 👨‍👩‍👦‍👦/PXL_20230817_202746758.LS.mp4 + 2702757 2024-05-25 22:15 Takeout/Google Photos/🇵🇹 Lisbonne ❤️ en famille 👨‍👩‍👦‍👦/PXL_20230818_072728336.jpg + 2015016 2024-05-25 22:15 Takeout/Google Photos/🇵🇹 Lisbonne ❤️ en famille 👨‍👩‍👦‍👦/PXL_20230818_082351912.jpg + 1969639 2024-05-25 22:15 Takeout/Google Photos/🇵🇹 Lisbonne ❤️ en famille 👨‍👩‍👦‍👦/PXL_20230818_082348579.jpg + 1789401 2024-05-25 22:15 Takeout/Google Photos/🇵🇹 Lisbonne ❤️ en famille 👨‍👩‍👦‍👦/PXL_20230818_080921955.jpg + 3342821 2024-05-25 22:15 Takeout/Google Photos/🇵🇹 Lisbonne ❤️ en famille 👨‍👩‍👦‍👦/PXL_20230818_073846874.jpg + 3243628 2024-05-25 22:15 Takeout/Google Photos/🇵🇹 Lisbonne ❤️ en famille 👨‍👩‍👦‍👦/PXL_20230818_073034374.jpg + 4464270 2024-05-25 22:15 Takeout/Google Photos/🇵🇹 Lisbonne ❤️ en famille 👨‍👩‍👦‍👦/PXL_20230818_073704846.jpg + 2910174 2024-05-25 22:15 Takeout/Google Photos/🇵🇹 Lisbonne ❤️ en famille 👨‍👩‍👦‍👦/PXL_20230818_074307497.jpg + 2336173 2024-05-25 22:15 Takeout/Google Photos/🇵🇹 Lisbonne ❤️ en famille 👨‍👩‍👦‍👦/PXL_20230818_130000489.jpg + 1929416 2024-05-25 22:15 Takeout/Google Photos/🇵🇹 Lisbonne ❤️ en famille 👨‍👩‍👦‍👦/PXL_20230818_132150855.jpg + 5934269 2024-05-25 22:15 Takeout/Google Photos/🇵🇹 Lisbonne ❤️ en famille 👨‍👩‍👦‍👦/PXL_20230818_081231702.jpg + 3169095 2024-05-25 22:15 Takeout/Google Photos/🇵🇹 Lisbonne ❤️ en famille 👨‍👩‍👦‍👦/PXL_20230818_144716103.jpg + 3046438 2024-05-25 22:15 Takeout/Google Photos/🇵🇹 Lisbonne ❤️ en famille 👨‍👩‍👦‍👦/PXL_20230818_134521846.jpg + 2138959 2024-05-25 22:15 Takeout/Google Photos/🇵🇹 Lisbonne ❤️ en famille 👨‍👩‍👦‍👦/PXL_20230818_161304257.jpg + 1531803 2024-05-25 22:15 Takeout/Google Photos/Garros 19 Juillet 2018/IMG_20180719_191638.jpg + 2974227 2024-05-25 22:15 Takeout/Google Photos/🇵🇹 Lisbonne ❤️ en famille 👨‍👩‍👦‍👦/PXL_20230818_144557167.jpg + 393806 2024-05-25 22:15 Takeout/Google Photos/Garros 19 Juillet 2018/IMG_8155.JPG + 485394 2024-05-25 22:15 Takeout/Google Photos/Garros 19 Juillet 2018/IMG_8152.JPG + 474952 2024-05-25 22:15 Takeout/Google Photos/Garros 19 Juillet 2018/IMG_8156.JPG + 2538601 2024-05-25 22:15 Takeout/Google Photos/🇵🇹 Lisbonne ❤️ en famille 👨‍👩‍👦‍👦/PXL_20230818_144231600.jpg + 496970 2024-05-25 22:15 Takeout/Google Photos/Garros 19 Juillet 2018/IMG_8157.JPG + 371649 2024-05-25 22:15 Takeout/Google Photos/Garros 19 Juillet 2018/IMG_8158.JPG + 3422738 2024-05-25 22:15 Takeout/Google Photos/🇵🇹 Lisbonne ❤️ en famille 👨‍👩‍👦‍👦/PXL_20230818_150420324.jpg + 723610 2024-05-25 22:15 Takeout/Google Photos/Garros 19 Juillet 2018/IMG_20180719_200157.jpg + 635305 2024-05-25 22:15 Takeout/Google Photos/Garros 19 Juillet 2018/IMG_8162.JPG + 708902 2024-05-25 22:15 Takeout/Google Photos/Garros 19 Juillet 2018/IMG_8163.JPG + 560297 2024-05-25 22:15 Takeout/Google Photos/Garros 19 Juillet 2018/IMG_8164.JPG + 381046 2024-05-25 22:15 Takeout/Google Photos/Garros 19 Juillet 2018/IMG_8167.JPG + 483752 2024-05-25 22:15 Takeout/Google Photos/Garros 19 Juillet 2018/IMG_8165.JPG + 456804 2024-05-25 22:15 Takeout/Google Photos/Garros 19 Juillet 2018/IMG_8166.JPG + 343792 2024-05-25 22:15 Takeout/Google Photos/Garros 19 Juillet 2018/IMG_8168.JPG + 367294 2024-05-25 22:15 Takeout/Google Photos/Garros 19 Juillet 2018/IMG_8169.JPG + 489839 2024-05-25 22:15 Takeout/Google Photos/Garros 19 Juillet 2018/IMG_8178.JPG + 669605 2024-05-25 22:15 Takeout/Google Photos/Garros 19 Juillet 2018/IMG_8170.JPG + 474541 2024-05-25 22:15 Takeout/Google Photos/Garros 19 Juillet 2018/IMG_8177.JPG + 1627237 2024-05-25 22:15 Takeout/Google Photos/Garros 19 Juillet 2018/IMG_8181.JPG + 548717 2024-05-25 22:15 Takeout/Google Photos/Garros 19 Juillet 2018/IMG_8179.JPG + 1951988 2024-05-25 22:15 Takeout/Google Photos/Garros 19 Juillet 2018/IMG_8172.JPG + 1419461 2024-05-25 22:15 Takeout/Google Photos/Garros 19 Juillet 2018/Bebop2_20180719211742+0200.jpg + 13156833 2024-05-25 22:15 Takeout/Google Photos/🇵🇹 Lisbonne ❤️ en famille 👨‍👩‍👦‍👦/PXL_20230818_073402211.TS.mp4 + 1729388 2024-05-25 22:15 Takeout/Google Photos/Garros 19 Juillet 2018/Bebop2_20180719211742+0200-modifié.jpg + 98595828 2024-05-25 22:15 Takeout/Google Photos/Garros 19 Juillet 2018/Bebop2_20180719211425+0200.mp4 +145104161 2024-05-25 22:15 Takeout/Google Photos/Garros 19 Juillet 2018/Bebop2_20180719185209+0200.mp4 + 89765082 2024-05-25 22:15 Takeout/Google Photos/Garros 19 Juillet 2018/Bebop2_20180719182934+0200.mp4 + 98016626 2024-05-25 22:15 Takeout/Google Photos/Garros 19 Juillet 2018/Bebop2_20180719194940+0200.mp4 +258577282 2024-05-25 22:15 Takeout/Google Photos/Garros 19 Juillet 2018/Bebop2_20180719201922+0200.mp4 +--------- ------- +1065090969 158 files +takeout-20240525T201456Z-003.zip: +Archive: takeout-20240525T201456Z-003.zip + Length Date Time Name +--------- ---------- ----- ---- +245068101 2024-05-25 22:15 Takeout/Google Photos/Garros 19 Juillet 2018/Bebop2_20180719203057+0200.mp4 +221047335 2024-05-25 22:15 Takeout/Google Photos/Garros 19 Juillet 2018/Bebop2_20180719185840+0200.mp4 +229274490 2024-05-25 22:15 Takeout/Google Photos/Garros 19 Juillet 2018/Bebop2_20180719183450+0200.mp4 +--------- ------- +695389926 3 files diff --git a/internal/fakefs/fakefs.go b/internal/fakefs/fakefs.go new file mode 100644 index 00000000..186b7a03 --- /dev/null +++ b/internal/fakefs/fakefs.go @@ -0,0 +1,212 @@ +package fakefs + +import ( + "crypto/rand" + "fmt" + "io" + "io/fs" + "path" + "path/filepath" + "sort" + "strings" + "time" + + "github.com/simulot/immich-go/helpers/gen" + "github.com/simulot/immich-go/immich/metadata" +) + +/* + simulate a file system based on the list of files contained into a set of archive. + +*/ + +type FakeDirEntry struct { + name string // name of the file + size int64 // length in bytes for regular files; system-dependent for others + mode fs.FileMode // file mode bits + modTime time.Time // modification time +} + +func (fi FakeDirEntry) Name() string { return path.Base(fi.name) } +func (fi FakeDirEntry) Size() int64 { return fi.size } +func (fi FakeDirEntry) Mode() fs.FileMode { return fi.mode } +func (fi FakeDirEntry) ModTime() time.Time { return fi.modTime } +func (fi FakeDirEntry) IsDir() bool { return fi.mode.IsDir() } +func (fi FakeDirEntry) Sys() any { return nil } +func (fi FakeDirEntry) Type() fs.FileMode { return fi.mode } +func (fi FakeDirEntry) Info() (fs.FileInfo, error) { return fi, nil } + +type FakeFile struct { + fi FakeDirEntry + r io.Reader + pos int64 +} + +func (f FakeFile) Stat() (fs.FileInfo, error) { + return f.fi, nil +} + +func (f *FakeFile) Read(b []byte) (int, error) { + if f.pos < f.fi.size { + n, err := f.r.Read(b) + f.pos += int64(n) + return n, err + } + return 0, io.EOF +} + +func (f *FakeFile) Close() error { + f.pos = 0 + return nil +} + +type FakeFS struct { + name string + files map[string]map[string]FakeDirEntry +} + +func (fsys FakeFS) Name() string { + return fsys.name +} + +func normalizeName(name string) string { + if name != "." && !strings.HasPrefix(name, "./") { + return "./" + name + } + return name +} + +func (fsys FakeFS) Stat(name string) (fs.FileInfo, error) { + name = normalizeName(name) + name = filepath.ToSlash(name) + dir, base := path.Split(name) + dir = strings.TrimSuffix(dir, "/") + var l map[string]FakeDirEntry + if dir == "" { + dir = "." + } + l = fsys.files[dir] + if len(l) == 0 { + return nil, fmt.Errorf("%s:%s: %w", fsys.name, name, fs.ErrNotExist) + } + if e, ok := l[base]; ok { + return e, nil + } + return nil, fs.ErrNotExist +} + +func (fsys FakeFS) Open(name string) (fs.File, error) { + name = normalizeName(name) + info, err := fsys.Stat(name) + if err != nil { + return nil, err + } + + fakeInfo := info.(FakeDirEntry) + var r io.Reader + + ext := path.Ext(name) + if strings.ToLower(ext) == ".json" { + base := path.Base(name) + switch base { + case "métadonnées.json", "metadata.json", "metadati.json", "metadáta.json", "Metadaten.json": + album := path.Base(path.Dir(name)) + r, fakeInfo.size = fakeAlbumData(album) + case "print-subscriptions.json", "shared_album_comments.json", "user-generated-memory-titles.json": + r, fakeInfo.size = fakeJSON() + default: + d := info.ModTime() + if d2 := metadata.TakeTimeFromName(name); !d2.IsZero() { + d = d2 + } + title := strings.TrimSuffix(path.Base(name), path.Ext(base)) + r, fakeInfo.size = fakePhotoData(title, d) + } + } else { + r = rand.Reader + } + return &FakeFile{fi: fakeInfo, r: r}, nil +} + +func (fsys FakeFS) ReadDir(name string) ([]fs.DirEntry, error) { + name = normalizeName(name) + info, err := fsys.Stat(name) + if err != nil { + return nil, err + } + if !info.IsDir() { + return nil, fs.ErrNotExist + } + + entries := fsys.files[name] + if len(entries) == 0 { + return nil, fs.ErrNotExist + } + + keys := gen.MapKeys(entries) + sort.Strings(keys) + out := []fs.DirEntry{} + for _, k := range keys { + if k != "." { + out = append(out, entries[k]) + } + } + return out, nil +} + +func (fsys FakeFS) addFile(name string, size int64, modDate time.Time) { + name = normalizeName(name) + dir, base := path.Split(name) + dir = strings.TrimSuffix(dir, "/") + parts := strings.Split(dir, "/") + + for i, p := range parts { + // create the entry in the parent + if i == 0 { + sub := "." + if _, ok := fsys.files[sub]; !ok { + // + e := FakeDirEntry{ + name: ".", + modTime: time.Now(), + size: 0, + mode: 0o777 | fs.ModeDir, + } + + fsys.files[sub] = map[string]FakeDirEntry{ + ".": e, + } + } + } else { + // add entry in the parent + parent := strings.Join(parts[:i], "/") + dir := parent + "/" + p + if _, ok := fsys.files[parent][p]; !ok { + fsys.files[parent][p] = FakeDirEntry{ + name: dir, + modTime: time.Now(), + size: 0, + mode: 0o777 | fs.ModeDir, + } + } + // create the dir entry + if _, ok := fsys.files[dir]; !ok { + fsys.files[dir] = map[string]FakeDirEntry{ + ".": { + name: dir + "/.", + modTime: time.Now(), + size: 0, + mode: 0o777 | fs.ModeDir, + }, + } + } + } + } + l := fsys.files[dir] + l[base] = FakeDirEntry{ + name: name, + modTime: modDate, + size: size, + mode: 0o777, + } +} diff --git a/internal/fakefs/metadata.go b/internal/fakefs/metadata.go new file mode 100644 index 00000000..1b7376fa --- /dev/null +++ b/internal/fakefs/metadata.go @@ -0,0 +1,77 @@ +package fakefs + +import ( + "fmt" + "io" + "strings" + "time" +) + +const albumTemplate = `{ + "title": "%s", + "description": "", + "access": "", + "date": { + "timestamp": "0", + "formatted": "1 janv. 1970, 00:00:00 UTC" + }, + "geoData": { + "latitude": 0.0, + "longitude": 0.0, + "altitude": 0.0, + "latitudeSpan": 0.0, + "longitudeSpan": 0.0 + } +}` + +func fakeAlbumData(name string) (io.Reader, int64) { + t := fmt.Sprintf(albumTemplate, name) + return strings.NewReader(t), int64(len(t)) +} + +const pictureTemplate = `{ + "title": "%[1]s", + "description": "", + "imageViews": "50", + "creationTime": { + "timestamp": "%[2]d" + }, + "photoTakenTime": { + "timestamp": "%[2]d" + }, + "geoData": { + "latitude": 48.0, + "longitude": 1.0, + "altitude": 102.86, + "latitudeSpan": 0.0, + "longitudeSpan": 0.0 + }, + "geoDataExif": { + "latitude": 48.0, + "longitude": 1.0, + "altitude": 102.86, + "latitudeSpan": 0.0, + "longitudeSpan": 0.0 + }, + "url": "https://photos.google.com/photo/AF1QipMZVTuUYj4K1jaN5vy6mkflX6yiWLQO2GDXSNKl", + "googlePhotosOrigin": { + "webUpload": { + "computerUpload": { + } + } + } +}` + +func fakePhotoData(name string, captureDate time.Time) (io.Reader, int64) { + t := fmt.Sprintf(pictureTemplate, name, captureDate.Unix()) + return strings.NewReader(t), int64(len(t)) +} + +const fakeJSONTemplate = `{ + "Nothing": "" +}` + +func fakeJSON() (io.Reader, int64) { + t := fakeJSONTemplate + return strings.NewReader(t), int64(len(t)) +} diff --git a/internal/fakefs/ziplist.go b/internal/fakefs/ziplist.go new file mode 100644 index 00000000..40094ff2 --- /dev/null +++ b/internal/fakefs/ziplist.go @@ -0,0 +1,92 @@ +package fakefs + +/* + for f in *.zip; do echo "$f: "; unzip -l $f; done >list.lst +*/ +import ( + "bufio" + "io" + "io/fs" + "os" + "regexp" + "sort" + "strconv" + "strings" + "time" + + "github.com/simulot/immich-go/helpers/gen" +) + +// ` 2104348 07-20-2023 00:00 Takeout/Google Photos/2020 - Costa Rica/IMG_3235.MP4` + +var reZipList = regexp.MustCompile(`(-rw-r--r-- 0/0\s+)?(\d+)\s+(.{16})\s+(.*)$`) + +func readFileLine(l string, dateFormat string) (string, int64, time.Time) { + if len(l) < 30 { + return "", 0, time.Time{} + } + m := reZipList.FindStringSubmatch(l) + if len(m) < 5 { + return "", 0, time.Time{} + } + size, _ := strconv.ParseInt(m[2], 10, 64) + modTime, _ := time.ParseInLocation(dateFormat, m[3], time.Local) + return m[4], size, modTime +} + +func ScanStringList(dateFormat string, s string) ([]fs.FS, error) { + r := strings.NewReader(s) + + return ScanFileListReader(r, dateFormat) +} + +func ScanFileList(name string, dateFormat string) ([]fs.FS, error) { + f, err := os.Open(name) + if err != nil { + return nil, err + } + defer f.Close() + return ScanFileListReader(f, dateFormat) +} + +func ScanFileListReader(f io.Reader, dateFormat string) ([]fs.FS, error) { + fsyss := map[string]*FakeFS{} + var fsys *FakeFS + currentZip := "" + ok := false + + scanner := bufio.NewScanner(f) + for scanner.Scan() { + l := scanner.Text() + if strings.HasPrefix(l, "Archive:") { + currentZip = strings.TrimSpace(strings.TrimPrefix(l, "Archive:")) + fsys, ok = fsyss[currentZip] + if !ok { + fsys = &FakeFS{ + name: currentZip, + files: map[string]map[string]FakeDirEntry{}, + } + + fsyss[currentZip] = fsys + } + continue + } + if name, size, modTime := readFileLine(l, dateFormat); name != "" { + fsys.addFile(name, size, modTime) + } + } + + if err := scanner.Err(); err != nil { + return nil, err + } + + names := gen.MapKeys(fsyss) + sort.Strings(names) + output := make([]fs.FS, len(fsyss)) + i := 0 + for _, name := range names { + output[i] = fsyss[name] + i++ + } + return output, nil +} diff --git a/internal/fakefs/ziplist_test.go b/internal/fakefs/ziplist_test.go new file mode 100644 index 00000000..91964f45 --- /dev/null +++ b/internal/fakefs/ziplist_test.go @@ -0,0 +1,118 @@ +package fakefs + +import ( + "fmt" + "io/fs" + "testing" + "time" +) + +func Test_readFileLine(t *testing.T) { + type args struct { + l string + dateFormat string + } + tests := []struct { + name string + args args + wantName string + wantModTime time.Time + wantSize int64 + }{ + { + name: "simulot", + args: args{ + l: " 145804 2024-05-25 22:15 Takeout/Google Photos/🇵🇹 Lisbonne ❤️ en famille 👨‍👩‍👦‍👦/😀😃😄😁😆😅😂🤣🥲☺️😊😇🙂🙃😉😌😍🥰😘😗😙😚😋😛.jpg", + dateFormat: "2006-01-02 15:04", + }, + wantName: "Takeout/Google Photos/🇵🇹 Lisbonne ❤️ en famille 👨‍👩‍👦‍👦/😀😃😄😁😆😅😂🤣🥲☺️😊😇🙂🙃😉😌😍🥰😘😗😙😚😋😛.jpg", + wantSize: 145804, + wantModTime: time.Date(2024, 5, 25, 22, 15, 0, 0, time.Local), + }, + { + name: "pixil", + args: args{ + l: " 197486 07-19-2023 23:53 Takeout/Google Photos/2011 - Omaha Zoo/IMG_20110702_153447.jpg", + dateFormat: "01-02-2006 15:04", + }, + wantName: "Takeout/Google Photos/2011 - Omaha Zoo/IMG_20110702_153447.jpg", + wantSize: 197486, + wantModTime: time.Date(2023, 7, 19, 23, 53, 0, 0, time.Local), + }, + { + name: "Phyl404", + args: args{ + l: "2555584471 2024-07-12 13:41 Takeout/Google Foto/Vultures 1/IMG_2002_580.MOV", + dateFormat: "2006-01-02 15:04", + }, + wantName: "Takeout/Google Foto/Vultures 1/IMG_2002_580.MOV", + wantSize: 2555584471, + wantModTime: time.Date(2024, 7, 12, 13, 41, 0, 0, time.Local), + }, + { + name: "tgz", + args: args{ + l: "-rw-r--r-- 0/0 717454980 2023-12-09 17:23 Takeout/Google Photos/Photos from 2019/VID_20190621_193014.mp4", + dateFormat: "2006-01-02 15:04", + }, + wantName: "Takeout/Google Photos/Photos from 2019/VID_20190621_193014.mp4", + wantModTime: time.Date(2023, 12, 9, 17, 23, 0, 0, time.Local), + wantSize: 717454980, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + gotName, gotSize, gotModTime := readFileLine(tt.args.l, tt.args.dateFormat) + + if gotName != tt.wantName { + t.Errorf("readFileLine() got = %v, want %v", gotName, tt.wantName) + } + if gotSize != tt.wantSize { + t.Errorf("readFileLine() got = %v, want %v", gotSize, tt.wantSize) + } + if !gotModTime.Equal(tt.wantModTime) { + t.Errorf("readFileLine() got = %v, want %v", gotModTime, tt.wantModTime) + } + }) + } +} + +func BenchmarkReadFileLine(b *testing.B) { + for i := 0; i < b.N; i++ { + _, _, _ = readFileLine(" 145804 2024-05-25 22:15 Takeout/Google Photos/🇵🇹 Lisbonne ❤️ en famille 👨‍👩‍👦‍👦/😀😃😄😁😆😅😂🤣🥲☺️😊😇🙂🙃😉😌😍🥰😘😗😙😚😋😛.jpg", "2006-01-02 15:04") + } +} + +type NameFS interface { + Name() string +} + +func TestFakeFS(t *testing.T) { + fsyss, err := ScanFileList("TESTDATA/small.lst", "2006-01-02 15:04") + if err != nil { + t.Error(err) + return + } + + for _, fsys := range fsyss { + if fsys, ok := fsys.(NameFS); ok { + fmt.Println(fsys.Name()) + } + err := fs.WalkDir(fsys, ".", + func(name string, d fs.DirEntry, err error) error { + if err != nil { + return err + } + f, err := d.Info() + if f != nil { + fmt.Printf("%9d %s %s\n", f.Size(), f.ModTime().Format("2006-01-02 15:04"), name) + } + return err + }) + if err != nil { + t.Error(err) + return + } + } + fmt.Println() +} diff --git a/readme.md b/readme.md index e14d5172..569d9bb6 100644 --- a/readme.md +++ b/readme.md @@ -74,7 +74,7 @@ Example: Immich-go check the server's SSL certificate. you can disable this beha | `-server=URL` | URL of the Immich service, example http://:2283 or https://your-domain | | | `-api=URL` | URL of the Immich api endpoint (http://container_ip:3301) | | | `-device-uuid=VALUE` | Force the device identification | `$HOSTNAME` | -| `-client-timeout=duration` | Set the timeout for server calls. The duration is a decimal number with a unit suffix, such as "300ms", "1.5m" or "45m". Valid time units are "ms", "s", "m", "h". | `5m` | +| `-client-timeout=duration` | Set the timeout for server calls. The duration is a decimal number with a unit suffix, such as "300ms", "1.5m" or "45m". Valid time units are "ms", "s", "m", "h". | `5m` | | `-skip-verify-ssl` | Skip SSL verification for use with self-signed certificates | `false` | | `-key=KEY` | A key generated by the user. Uploaded photos will belong to the key's owner. | | | `-log-level=LEVEL` | Adjust the log verbosity as follows:
- `ERROR`: Display only errors
- `WARNING`: Same as previous one plus non-blocking error
- `INFO`: Information messages | `INFO` | @@ -82,8 +82,8 @@ Example: Immich-go check the server's SSL certificate. you can disable this beha | `-log-json` | Output the log as line-delimited JSON file | `false` | | `-time-zone=time_zone_name` | Set the time zone for dates without time zone information | the system's time zone | | `-no-ui` | Disable the user interface | `false` | -| `-debug-counters` | Enable the generation a CSV beside the log file | `false` | -| `-api-trace` | Enable trace of API calls | `false` | +| `-debug-counters` | Enable the generation a CSV beside the log file | `false` | +| `-api-trace` | Enable trace of API calls | `false` | ## Command `upload` @@ -91,18 +91,18 @@ 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. | `TRUE` | -| `-stack-jpg-raw` | Control the stacking of jpg/raw photos. | `TRUE` | -| `-stack-burst` | Control the stacking bursts. | `TRUE` | -| `-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/`| +| **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. | `FALS` | +| `-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: Fine-tune import based on specific dates: @@ -142,6 +142,7 @@ Specialized options for Google Photos management: | `-keep-partner` | Specifies inclusion or exclusion of partner-taken photos. | `TRUE` | | `-partner-album="partner's album"` | import assets from partner into given album. | | | `-discard-archived` | don't import archived assets. | `FALSE` | +| `-upload-when-missing-JSON` | Upload photos not associated with a JSON metadata file | `FALSE` | Read [here](docs/google-takeout.md) to understand how Google Photos takeout isn't easy to handle.