Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

chore: follow immich 1.95.0 API changes #170

Merged
merged 2 commits into from
Feb 27, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
2 changes: 1 addition & 1 deletion cmd/duplicate/duplicate.go
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,7 @@ func DuplicateCommand(ctx context.Context, common *cmd.SharedFlags, args []strin

dupCount := 0
app.Jnl.Log.MessageContinue(logger.OK, "Get server's assets...")
err = app.Immich.GetAllAssetsWithFilter(ctx, nil, func(a *immich.Asset) {
err = app.Immich.GetAllAssetsWithFilter(ctx, func(a *immich.Asset) {
if a.IsTrashed {
return
}
Expand Down
2 changes: 1 addition & 1 deletion cmd/metadata/metadata.go
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,7 @@ func MetadataCommand(ctx context.Context, common *cmd.SharedFlags, args []string
}

app.Jnl.Log.MessageContinue(logger.OK, "Get server's assets...")
list, err := app.Immich.GetAllAssets(ctx, nil)
list, err := app.Immich.GetAllAssets(ctx)
if err != nil {
return err
}
Expand Down
2 changes: 1 addition & 1 deletion cmd/stack/stack.go
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,7 @@ func NewStackCommand(ctx context.Context, common *cmd.SharedFlags, args []string
app.Jnl.Log.MessageContinue(logger.OK, "Get server's assets...")
assetCount := 0

err = app.Immich.GetAllAssetsWithFilter(ctx, nil, func(a *immich.Asset) {
err = app.Immich.GetAllAssetsWithFilter(ctx, func(a *immich.Asset) {
if a.IsTrashed {
return
}
Expand Down
4 changes: 2 additions & 2 deletions cmd/upload/e2e_upload_folder_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -390,7 +390,7 @@ func resetImmich(ic *immich.ImmichClient, user string) error {
}
}

assets, err := ic.GetAllAssets(context.Background(), nil)
assets, err := ic.GetAllAssets(context.Background())
if err != nil {
return err
}
Expand All @@ -405,7 +405,7 @@ func resetImmich(ic *immich.ImmichClient, user string) error {

attempts := 5
for attempts > 0 {
assets, err := ic.GetAllAssets(context.Background(), nil)
assets, err := ic.GetAllAssets(context.Background())
if err != nil {
return err
}
Expand Down
2 changes: 1 addition & 1 deletion cmd/upload/upload.go
Original file line number Diff line number Diff line change
Expand Up @@ -164,7 +164,7 @@ func NewUpCmd(ctx context.Context, common *cmd.SharedFlags, args []string) (*UpC
}
app.Jnl.Log.OK("Ask for server's assets...")
var list []*immich.Asset
err = app.Immich.GetAllAssetsWithFilter(ctx, nil, func(a *immich.Asset) {
err = app.Immich.GetAllAssetsWithFilter(ctx, func(a *immich.Asset) {
if a.IsTrashed {
return
}
Expand Down
4 changes: 2 additions & 2 deletions cmd/upload/upload_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ import (

type stubIC struct{}

func (c *stubIC) GetAllAssetsWithFilter(context.Context, *immich.GetAssetOptions, func(*immich.Asset)) error {
func (c *stubIC) GetAllAssetsWithFilter(context.Context, func(*immich.Asset)) error {
return nil
}

Expand Down Expand Up @@ -77,7 +77,7 @@ func (c *stubIC) GetAssetAlbums(ctx context.Context, id string) ([]immich.AlbumS
return nil, nil
}

func (c *stubIC) GetAllAssets(ctx context.Context, opt *immich.GetAssetOptions) ([]*immich.Asset, error) {
func (c *stubIC) GetAllAssets(ctx context.Context) ([]*immich.Asset, error) {
return nil, nil
}

Expand Down
58 changes: 6 additions & 52 deletions immich/asset.go
Original file line number Diff line number Diff line change
Expand Up @@ -174,57 +174,6 @@ func (o *GetAssetOptions) Values() url.Values {
return v
}

// GetAllAssets get all user's assets using the paged API searchAssets
//
// It calls the server for IMAGE, VIDEO, normal item, trashed Items

func (ic *ImmichClient) GetAllAssets(ctx context.Context, opt *GetAssetOptions) ([]*Asset, error) {
var r []*Asset

for _, t := range []string{"IMAGE", "VIDEO", "AUDIO", "OTHER"} {
values := opt.Values()
values.Set("type", t)
values.Set("withExif", "true")
values.Set("isVisible", "true")
values.Del("trashedBefore")
err := ic.newServerCall(ctx, "GetAllAssets", setPaginator()).do(get("/assets", setURLValues(values), setAcceptJSON()), responseAccumulateJSON(&r))
if err != nil {
return r, err
}
values.Set("trashedBefore", "9999-01-01")
err = ic.newServerCall(ctx, "GetAllAssets", setPaginator()).do(get("/assets", setURLValues(values), setAcceptJSON()), responseAccumulateJSON(&r))
if err != nil {
return r, err
}
}
return r, nil
}

// GetAllAssetsWithFilter get all user's assets using the paged API searchAssets and apply a filter
// TODO: rename this function, it's not a filter, it uses a callback function for each item
//
// It calls the server for IMAGE, VIDEO, normal item, trashed Items
func (ic *ImmichClient) GetAllAssetsWithFilter(ctx context.Context, opt *GetAssetOptions, filter func(*Asset)) error {
for _, t := range []string{"IMAGE", "VIDEO", "AUDIO", "OTHER"} {
values := opt.Values()
values.Set("type", t)
values.Set("withExif", "true")
values.Set("isVisible", "true")
values.Del("trashedBefore")
err := ic.newServerCall(ctx, "GetAllAssets", setPaginator()).do(get("/assets", setURLValues(values), setAcceptJSON()), responseJSONWithFilter(filter))
if err != nil {
return err
}
values.Set("trashedBefore", "9999-01-01")
err = ic.newServerCall(ctx, "GetAllAssets", setPaginator()).do(get("/assets", setURLValues(values), setAcceptJSON()), responseJSONWithFilter(filter))
if err != nil {
return err
}
}

return nil
}

func (ic *ImmichClient) DeleteAssets(ctx context.Context, id []string, forceDelete bool) error {
req := struct {
Force bool `json:"force"`
Expand All @@ -238,8 +187,13 @@ func (ic *ImmichClient) DeleteAssets(ctx context.Context, id []string, forceDele
}

func (ic *ImmichClient) GetAssetByID(ctx context.Context, id string) (*Asset, error) {
body := struct {
WithExif bool `json:"withExif,omitempty"`
IsVisible bool `json:"isVisible,omitempty"`
ID string `json:"id"`
}{WithExif: true, IsVisible: true, ID: id}
r := Asset{}
err := ic.newServerCall(ctx, "GetAssetByID").do(get("/asset/assetById/"+id, setAcceptJSON()), responseJSON(&r))
err := ic.newServerCall(ctx, "GetAssetByID").do(post("/search/metadata", "application/json", setAcceptJSON(), setJSONBody(body)), responseJSON(&r))
return &r, err
}

Expand Down
100 changes: 15 additions & 85 deletions immich/call.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,6 @@ import (
"fmt"
"io"
"net/http"
"net/url"
"strconv"
"strings"
)

Expand All @@ -28,11 +26,8 @@ type serverCall struct {
ic *ImmichClient
err error
ctx context.Context
p *paginator
}

type serverCallOption func(sc *serverCall) error

// callError represents errors returned by the server
type callError struct {
endPoint string
Expand Down Expand Up @@ -85,17 +80,12 @@ func (ce callError) Error() string {
return b.String()
}

func (ic *ImmichClient) newServerCall(ctx context.Context, api string, opts ...serverCallOption) *serverCall {
func (ic *ImmichClient) newServerCall(ctx context.Context, api string) *serverCall {
sc := &serverCall{
endPoint: api,
ic: ic,
ctx: ctx,
}
if sc.err == nil {
for _, opt := range opts {
_ = sc.joinError(opt(sc))
}
}
return sc
}

Expand All @@ -120,32 +110,6 @@ func (sc *serverCall) joinError(err error) error {
return err
}

// paginator controls the paged API calls
type paginator struct {
pageNumber int // current page
pageParameter string // page parameter name on the URL
EOF bool // true when the last page was empty
}

func (p paginator) setPage(v url.Values) {
v.Set(p.pageParameter, strconv.Itoa(p.pageNumber))
}

func (p *paginator) nextPage() {
p.pageNumber++
}

func setPaginator() serverCallOption {
return func(sc *serverCall) error {
p := paginator{
pageParameter: "page",
pageNumber: 1,
}
sc.p = &p
return nil
}
}

type requestFunction func(sc *serverCall) *http.Request

func (sc *serverCall) request(method string, url string, opts ...serverRequestOption) *http.Request {
Expand Down Expand Up @@ -199,25 +163,6 @@ func put(url string, opts ...serverRequestOption) requestFunction {
}

func (sc *serverCall) do(fnRequest requestFunction, opts ...serverResponseOption) error {
if sc.err != nil || fnRequest == nil {
return sc.Err(nil, nil, nil)
}

if sc.p == nil {
return sc._callDo(fnRequest, opts...)
}

for !sc.p.EOF {
err := sc._callDo(fnRequest, opts...)
if err != nil {
return err
}
sc.p.nextPage()
}
return nil
}

func (sc *serverCall) _callDo(fnRequest requestFunction, opts ...serverResponseOption) error {
var (
resp *http.Response
err error
Expand All @@ -228,11 +173,6 @@ func (sc *serverCall) _callDo(fnRequest requestFunction, opts ...serverResponseO
return sc.Err(req, nil, nil)
}

if sc.p != nil {
v := req.URL.Query()
sc.p.setPage(v)
req.URL.RawQuery = v.Encode()
}
if sc.ic.APITrace /* && req.Header.Get("Content-Type") == "application/json"*/ {
_ = sc.joinError(setTraceJSONRequest()(sc, req))
}
Expand Down Expand Up @@ -316,21 +256,6 @@ func setContentType(cType string) serverRequestOption {
}
}

func setURLValues(values url.Values) serverRequestOption {
return func(sc *serverCall, req *http.Request) error {
if values != nil {
rValues := req.URL.Query()
for k, v := range values {
for _, s := range v {
rValues.Set(k, s)
}
}
req.URL.RawQuery = rValues.Encode()
}
return nil
}
}

type serverResponseOption func(sc *serverCall, resp *http.Response) error

func responseJSON[T any](object *T) serverResponseOption {
Expand All @@ -349,11 +274,10 @@ func responseJSON[T any](object *T) serverResponseOption {
}
}

/*
func responseAccumulateJSON[T any](acc *[]T) serverResponseOption {
return func(sc *serverCall, resp *http.Response) error {
if sc.p != nil {
sc.p.EOF = true
}
eof := true
if resp != nil {
if resp.Body != nil {
defer resp.Body.Close()
Expand All @@ -366,21 +290,23 @@ func responseAccumulateJSON[T any](acc *[]T) serverResponseOption {
return err
}
if len(arr) > 0 && sc.p != nil {
sc.p.EOF = false
eof = false
}
(*acc) = append((*acc), arr...)
if eof {
sc.p.setEOF()
}
return nil
}
}
return errors.New("can't decode nil response")
}
}

*/
/*
func responseJSONWithFilter[T any](filter func(*T)) serverResponseOption {
return func(sc *serverCall, resp *http.Response) error {
if sc.p != nil {
sc.p.EOF = true
}
eof := true
if resp != nil {
if resp.Body != nil {
defer resp.Body.Close()
Expand All @@ -403,15 +329,19 @@ func responseJSONWithFilter[T any](filter func(*T)) serverResponseOption {
return err
}
if sc.p != nil {
sc.p.EOF = false
eof = false
}
filter(&o)
}
// read closing bracket "]"
_, err = dec.Token()
if eof {
sc.p.setEOF()
}
return err
}
}
return errors.New("can't decode nil response")
}
}
*/