|
package google_photo |
|
|
|
import ( |
|
"fmt" |
|
"net/http" |
|
|
|
"github.com/alist-org/alist/v3/drivers/base" |
|
"github.com/go-resty/resty/v2" |
|
) |
|
|
|
|
|
|
|
const ( |
|
FETCH_ALL = "all" |
|
FETCH_ALBUMS = "albums" |
|
FETCH_ROOT = "root" |
|
FETCH_SHARE_ALBUMS = "share_albums" |
|
) |
|
|
|
func (d *GooglePhoto) refreshToken() error { |
|
url := "https://www.googleapis.com/oauth2/v4/token" |
|
var resp base.TokenResp |
|
var e TokenError |
|
_, err := base.RestyClient.R().SetResult(&resp).SetError(&e). |
|
SetFormData(map[string]string{ |
|
"client_id": d.ClientID, |
|
"client_secret": d.ClientSecret, |
|
"refresh_token": d.RefreshToken, |
|
"grant_type": "refresh_token", |
|
}).Post(url) |
|
if err != nil { |
|
return err |
|
} |
|
if e.Error != "" { |
|
return fmt.Errorf(e.Error) |
|
} |
|
d.AccessToken = resp.AccessToken |
|
return nil |
|
} |
|
|
|
func (d *GooglePhoto) request(url string, method string, callback base.ReqCallback, resp interface{}, headers map[string]string) ([]byte, error) { |
|
req := base.RestyClient.R() |
|
req.SetHeader("Authorization", "Bearer "+d.AccessToken) |
|
req.SetHeader("Accept-Encoding", "gzip") |
|
if headers != nil { |
|
req.SetHeaders(headers) |
|
} |
|
|
|
if callback != nil { |
|
callback(req) |
|
} |
|
if resp != nil { |
|
req.SetResult(resp) |
|
} |
|
var e Error |
|
req.SetError(&e) |
|
res, err := req.Execute(method, url) |
|
if err != nil { |
|
return nil, err |
|
} |
|
if e.Error.Code != 0 { |
|
if e.Error.Code == 401 { |
|
err = d.refreshToken() |
|
if err != nil { |
|
return nil, err |
|
} |
|
return d.request(url, method, callback, resp, headers) |
|
} |
|
return nil, fmt.Errorf("%s: %v", e.Error.Message, e.Error.Errors) |
|
} |
|
return res.Body(), nil |
|
} |
|
|
|
func (d *GooglePhoto) getFiles(id string) ([]MediaItem, error) { |
|
switch id { |
|
case FETCH_ALL: |
|
return d.getAllMedias() |
|
case FETCH_ALBUMS: |
|
return d.getAlbums() |
|
case FETCH_SHARE_ALBUMS: |
|
return d.getShareAlbums() |
|
case FETCH_ROOT: |
|
return d.getFakeRoot() |
|
default: |
|
return d.getMedias(id) |
|
} |
|
} |
|
|
|
func (d *GooglePhoto) getFakeRoot() ([]MediaItem, error) { |
|
return []MediaItem{ |
|
{ |
|
Id: FETCH_ALL, |
|
Title: "全部媒体", |
|
}, |
|
{ |
|
Id: FETCH_ALBUMS, |
|
Title: "全部影集", |
|
}, |
|
{ |
|
Id: FETCH_SHARE_ALBUMS, |
|
Title: "共享影集", |
|
}, |
|
}, nil |
|
} |
|
|
|
func (d *GooglePhoto) getAlbums() ([]MediaItem, error) { |
|
return d.fetchItems( |
|
"https://photoslibrary.googleapis.com/v1/albums", |
|
map[string]string{ |
|
"fields": "albums(id,title,coverPhotoBaseUrl),nextPageToken", |
|
"pageSize": "50", |
|
"pageToken": "first", |
|
}, |
|
http.MethodGet) |
|
} |
|
|
|
func (d *GooglePhoto) getShareAlbums() ([]MediaItem, error) { |
|
return d.fetchItems( |
|
"https://photoslibrary.googleapis.com/v1/sharedAlbums", |
|
map[string]string{ |
|
"fields": "sharedAlbums(id,title,coverPhotoBaseUrl),nextPageToken", |
|
"pageSize": "50", |
|
"pageToken": "first", |
|
}, |
|
http.MethodGet) |
|
} |
|
|
|
func (d *GooglePhoto) getMedias(albumId string) ([]MediaItem, error) { |
|
return d.fetchItems( |
|
"https://photoslibrary.googleapis.com/v1/mediaItems:search", |
|
map[string]string{ |
|
"fields": "mediaItems(id,baseUrl,mimeType,mediaMetadata,filename),nextPageToken", |
|
"pageSize": "100", |
|
"albumId": albumId, |
|
"pageToken": "first", |
|
}, http.MethodPost) |
|
} |
|
|
|
func (d *GooglePhoto) getAllMedias() ([]MediaItem, error) { |
|
return d.fetchItems( |
|
"https://photoslibrary.googleapis.com/v1/mediaItems", |
|
map[string]string{ |
|
"fields": "mediaItems(id,baseUrl,mimeType,mediaMetadata,filename),nextPageToken", |
|
"pageSize": "100", |
|
"pageToken": "first", |
|
}, |
|
http.MethodGet) |
|
} |
|
|
|
func (d *GooglePhoto) getMedia(id string) (MediaItem, error) { |
|
var resp MediaItem |
|
|
|
query := map[string]string{ |
|
"fields": "mediaMetadata,baseUrl,mimeType", |
|
} |
|
_, err := d.request(fmt.Sprintf("https://photoslibrary.googleapis.com/v1/mediaItems/%s", id), http.MethodGet, func(req *resty.Request) { |
|
req.SetQueryParams(query) |
|
}, &resp, nil) |
|
if err != nil { |
|
return resp, err |
|
} |
|
|
|
return resp, nil |
|
} |
|
|
|
func (d *GooglePhoto) fetchItems(url string, query map[string]string, method string) ([]MediaItem, error){ |
|
res := make([]MediaItem, 0) |
|
for query["pageToken"] != "" { |
|
if query["pageToken"] == "first" { |
|
query["pageToken"] = "" |
|
} |
|
var resp Items |
|
|
|
_, err := d.request(url, method, func(req *resty.Request) { |
|
req.SetQueryParams(query) |
|
}, &resp, nil) |
|
if err != nil { |
|
return nil, err |
|
} |
|
query["pageToken"] = resp.NextPageToken |
|
res = append(res, resp.MediaItems...) |
|
res = append(res, resp.Albums...) |
|
res = append(res, resp.SharedAlbums...) |
|
} |
|
return res, nil |
|
} |
|
|