Skip to content

Commit

Permalink
fix #29 date comparison before uploading file
Browse files Browse the repository at this point in the history
  • Loading branch information
simulot committed Oct 9, 2023
1 parent d9b0165 commit 61bb736
Show file tree
Hide file tree
Showing 18 changed files with 185 additions and 71 deletions.
2 changes: 1 addition & 1 deletion assets/gp/googlephotos.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ package gp
import (
"context"
"immich-go/assets"
"immich-go/fshelper"
"immich-go/helpers/fshelper"
"io/fs"
"path"
"regexp"
Expand Down
6 changes: 4 additions & 2 deletions assets/gp/json.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package gp
import (
"encoding/json"
"fmt"
"immich-go/helpers/tzone"
"strconv"
"time"
)
Expand Down Expand Up @@ -59,8 +60,9 @@ type googTimeObject struct {
// Time return the time.Time of the epoch
func (gt googTimeObject) Time() time.Time {
t := time.Unix(gt.Timestamp, 0)
t = time.Date(t.Year(), t.Month(), t.Day(), t.Hour(), t.Minute(), t.Second(), t.Nanosecond(), time.UTC)
return t
local, _ := tzone.Local()
// t = time.Date(t.Year(), t.Month(), t.Day(), t.Hour(), t.Minute(), t.Second(), t.Nanosecond(), time.UTC)
return t.In(local)
}

// UnmarshalJSON read the googTimeObject from the json
Expand Down
2 changes: 1 addition & 1 deletion assets/localfile.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ package assets
import (
"errors"
"fmt"
"immich-go/fshelper"
"immich-go/helpers/fshelper"
"immich-go/immich/metadata"
"io"
"io/fs"
Expand Down
4 changes: 2 additions & 2 deletions cmdduplicate/duplicate.go
Original file line number Diff line number Diff line change
Expand Up @@ -74,9 +74,9 @@ func DuplicateCommand(ctx context.Context, ic *immich.ImmichClient, log *logger.
return ctx.Err()
default:
count++
if app.DateRange.InRange(a.ExifInfo.DateTimeOriginal) {
if app.DateRange.InRange(a.ExifInfo.DateTimeOriginal.Time) {
k := duplicateKey{
Date: a.ExifInfo.DateTimeOriginal,
Date: a.ExifInfo.DateTimeOriginal.Time,
Name: strings.ToUpper(a.OriginalFileName + path.Ext(a.OriginalPath)),
}
l := duplicate[k]
Expand Down
2 changes: 1 addition & 1 deletion cmdmetadata/metadatacmd.go
Original file line number Diff line number Diff line change
Expand Up @@ -83,7 +83,7 @@ func MetadataCommand(ctx context.Context, ic *immich.ImmichClient, log *logger.L
if app.MissingDateDespiteName {
dt := metadata.TakeTimeFromName(path.Base(a.OriginalPath))
if !dt.IsZero() {
if a.ExifInfo.DateTimeOriginal.IsZero() || (math.Abs(float64(dt.Sub(a.ExifInfo.DateTimeOriginal))) > float64(24.0*time.Hour)) {
if a.ExifInfo.DateTimeOriginal.IsZero() || (math.Abs(float64(dt.Sub(a.ExifInfo.DateTimeOriginal.Time))) > float64(24.0*time.Hour)) {
ba.reason = append(ba.reason, "capture date invalid, but the name contains a date")
ba.fixable = true
ba.SideCar.DateTaken = dt
Expand Down
4 changes: 2 additions & 2 deletions cmdupload/assets.go
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ func (ai *AssetIndex) ReIndex() {
l = append(l, a)
ai.byHash[a.Checksum] = l

n := a.OriginalFileName
n := a.OriginalFileName + ext
l = ai.byName[n]
l = append(l, a)
ai.byName[n] = l
Expand All @@ -47,7 +47,7 @@ func (ai *AssetIndex) AddLocalAsset(la *assets.LocalAssetFile, ImmichID string)
OriginalFileName: strings.TrimSuffix(path.Base(la.Title), path.Ext(la.Title)),
ExifInfo: immich.ExifInfo{
FileSizeInByte: int(la.Size()),
DateTimeOriginal: la.DateTaken,
DateTimeOriginal: immich.ImmichTime{Time: la.DateTaken},
Latitude: la.Latitude,
Longitude: la.Longitude,
},
Expand Down
16 changes: 14 additions & 2 deletions cmdupload/upload.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ import (
"immich-go/assets"
"immich-go/assets/files"
"immich-go/assets/gp"
"immich-go/fshelper"
"immich-go/helpers/fshelper"
"immich-go/immich"
"immich-go/immich/logger"
"immich-go/immich/metadata"
Expand Down Expand Up @@ -583,7 +583,7 @@ func (ai *AssetIndex) ShouldUpload(la *assets.LocalAssetFile) (*Advice, error) {

}
for _, sa = range l {
compareDate := dateTaken.Compare(sa.ExifInfo.DateTimeOriginal)
compareDate := compareDate(dateTaken, sa.ExifInfo.DateTimeOriginal.Time)
compareSize := size - sa.ExifInfo.FileSizeInByte

switch {
Expand All @@ -599,6 +599,18 @@ func (ai *AssetIndex) ShouldUpload(la *assets.LocalAssetFile) (*Advice, error) {
return ai.adviceNotOnServer(), nil
}

func compareDate(d1 time.Time, d2 time.Time) int {
diff := d1.Sub(d2)

switch {
case diff < -5*time.Minute:
return -1
case diff >= 5*time.Minute:
return +1
}
return 0
}

// hasMeta reports whether path contains any of the magic characters
// recognized by Match.
// shamelessly copied from stdlib/os
Expand Down
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
26 changes: 26 additions & 0 deletions helpers/tzone/timezone.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
package tzone

import (
"strings"
"sync"
"time"
)

var (
_local *time.Location
_err error
onceSetLocal sync.Once
)

func Local() (*time.Location, error) {
onceSetLocal.Do(func() {
var tz string
tz, _err = getTimezoneName()
if _err != nil {
return
}

_local, _err = time.LoadLocation(strings.TrimSuffix(tz, "\n"))
})
return _local, _err
}
17 changes: 17 additions & 0 deletions helpers/tzone/tz_darwin.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
//go:build darwin

package tzone

import (
"os/exec"
)

func getTimezoneName() (string, error) {
cmd := exec.Command("systemsetup", "-gettimezone")
output, err := cmd.Output()
if err != nil {
return "", err
}

return string(output), nil
}
13 changes: 13 additions & 0 deletions helpers/tzone/tz_unix.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
//go:build unix

package tzone

import "os"

func getTimezoneName() (string, error) {
data, err := os.ReadFile("/etc/timezone")
if err != nil {
return "", err
}
return string(data), nil
}
23 changes: 23 additions & 0 deletions helpers/tzone/tz_windows.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
//go:build windows

package tzone

import (
"golang.org/x/sys/windows/registry"
)

func getTimezoneName() (string, error) {
key, err := registry.OpenKey(registry.LOCAL_MACHINE, `SYSTEM\CurrentControlSet\Control\TimeZoneInformation`, registry.QUERY_VALUE)
if err != nil {
return "", err
}
defer key.Close()

var timeZoneName string
if val, valType, err := key.GetStringValue("TimeZoneKeyName"); err == nil && valType == registry.SZ {
timeZoneName = val
} else {
return "", err
}
return timeZoneName, nil
}
50 changes: 1 addition & 49 deletions immich/asset.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import (
"context"
"fmt"
"immich-go/assets"
"immich-go/fshelper"
"immich-go/helpers/fshelper"
"io"
"mime/multipart"
"net/textproto"
Expand All @@ -14,54 +14,6 @@ import (
"time"
)

// immich Asset simplified
type Asset struct {
ID string `json:"id"`
DeviceAssetID string `json:"deviceAssetId"`
OwnerID string `json:"ownerId"`
DeviceID string `json:"deviceId"`
Type string `json:"type"`
OriginalPath string `json:"originalPath"`
OriginalFileName string `json:"originalFileName"`
Resized bool `json:"resized"`
Thumbhash string `json:"thumbhash"`
FileCreatedAt time.Time `json:"fileCreatedAt"`
FileModifiedAt time.Time `json:"fileModifiedAt"`
UpdatedAt time.Time `json:"updatedAt"`
IsFavorite bool `json:"isFavorite"`
IsArchived bool `json:"isArchived"`
Duration string `json:"duration"`
ExifInfo ExifInfo `json:"exifInfo"`
LivePhotoVideoID any `json:"livePhotoVideoId"`
Tags []any `json:"tags"`
Checksum string `json:"checksum"`
JustUploaded bool `json:"-"`
Albums []AlbumSimplified `json:"-"` // Albums that asset belong to
}

type ExifInfo struct {
Make string `json:"make"`
Model string `json:"model"`
ExifImageWidth int `json:"exifImageWidth"`
ExifImageHeight int `json:"exifImageHeight"`
FileSizeInByte int `json:"fileSizeInByte"`
Orientation string `json:"orientation"`
DateTimeOriginal time.Time `json:"dateTimeOriginal,omitempty"`
// ModifyDate time.Time `json:"modifyDate"`
TimeZone string `json:"timeZone"`
// LensModel string `json:"lensModel"`
// FNumber float64 `json:"fNumber"`
// FocalLength float64 `json:"focalLength"`
// Iso int `json:"iso"`
// ExposureTime string `json:"exposureTime"`
Latitude float64 `json:"latitude,omitempty"`
Longitude float64 `json:"longitude,omitempty"`
// City string `json:"city"`
// State string `json:"state"`
// Country string `json:"country"`
// Description string `json:"description"`
}

type AssetResponse struct {
ID string `json:"id"`
Duplicate bool `json:"duplicate"`
Expand Down
11 changes: 0 additions & 11 deletions immich/client.go
Original file line number Diff line number Diff line change
Expand Up @@ -62,14 +62,3 @@ func (ic *ImmichClient) ValidateConnection(ctx context.Context) (User, error) {
}
return user, nil
}

// // Get all asset IDs belonging to the user
// func (ic *ImmichClient) GetUserAssetsByDeviceId(deviceID string) (*StringList, error) {
// list := StringList{}
// err := ic.newServerCall("GetUserAssetsByDeviceId").
// do(get("/asset/"+ic.DeviceUUID, setAcceptJSON()), responseJSON(&list))
// if err != nil {
// return &list, err
// }
// return &list, nil
// }
80 changes: 80 additions & 0 deletions immich/immich.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package immich
import (
"encoding/json"
"errors"
"immich-go/helpers/tzone"
"sync"
"time"
)
Expand Down Expand Up @@ -85,3 +86,82 @@ func (b myBool) String() string {
}
return "false"
}

// immich Asset simplified
type Asset struct {
ID string `json:"id"`
DeviceAssetID string `json:"deviceAssetId"`
OwnerID string `json:"ownerId"`
DeviceID string `json:"deviceId"`
Type string `json:"type"`
OriginalPath string `json:"originalPath"`
OriginalFileName string `json:"originalFileName"`
Resized bool `json:"resized"`
Thumbhash string `json:"thumbhash"`
FileCreatedAt ImmichTime `json:"fileCreatedAt"`
FileModifiedAt ImmichTime `json:"fileModifiedAt"`
UpdatedAt ImmichTime `json:"updatedAt"`
IsFavorite bool `json:"isFavorite"`
IsArchived bool `json:"isArchived"`
Duration string `json:"duration"`
ExifInfo ExifInfo `json:"exifInfo"`
LivePhotoVideoID any `json:"livePhotoVideoId"`
Tags []any `json:"tags"`
Checksum string `json:"checksum"`
JustUploaded bool `json:"-"`
Albums []AlbumSimplified `json:"-"` // Albums that asset belong to
}

type ExifInfo struct {
Make string `json:"make"`
Model string `json:"model"`
ExifImageWidth int `json:"exifImageWidth"`
ExifImageHeight int `json:"exifImageHeight"`
FileSizeInByte int `json:"fileSizeInByte"`
Orientation string `json:"orientation"`
DateTimeOriginal ImmichTime `json:"dateTimeOriginal,omitempty"`
// ModifyDate time.Time `json:"modifyDate"`
TimeZone string `json:"timeZone"`
// LensModel string `json:"lensModel"`
// FNumber float64 `json:"fNumber"`
// FocalLength float64 `json:"focalLength"`
// Iso int `json:"iso"`
// ExposureTime string `json:"exposureTime"`
Latitude float64 `json:"latitude,omitempty"`
Longitude float64 `json:"longitude,omitempty"`
// City string `json:"city"`
// State string `json:"state"`
// Country string `json:"country"`
// Description string `json:"description"`
}

type ImmichTime struct {
time.Time
}

// ImmichTime.UnmarshalJSON read time from the JSON string.
// The json provides a time UTC, but the server and the images dates are given in local time.
// The get the correct time into the struct, we capture the UTC time and return it in the local zone.
//
// workaround for: error at connection to immich server: cannot parse "+174510-04-28T00:49:44.000Z" as "2006" #28
// capture the error

func (t *ImmichTime) UnmarshalJSON(b []byte) error {
local, err := tzone.Local()
if err != nil {
return err
}
var ts time.Time
if len(b) < 3 {
t.Time = time.Time{}
return nil
}
b = b[1 : len(b)-1]
ts, err = time.ParseInLocation("2006-01-02T15:04:05.000Z", string(b), time.UTC)
if err != nil {
t.Time = time.Time{}
return nil
}
t.Time = ts.In(local)
return nil
}

0 comments on commit 61bb736

Please # to comment.