feat(google_photo): Add categories in root, add album support. (#2046)

* feat(google_photo): Add categories in root, add album support.

* fix(google_photo): Remove else block in `drive/google_photo/types.go:60`
pull/2058/head
Jake Liu 2022-10-18 15:19:05 +08:00 committed by GitHub
parent 45cc0cedbd
commit 3db798a82a
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 137 additions and 39 deletions

View File

@ -43,7 +43,7 @@ func (d *GooglePhoto) Drop(ctx context.Context) error {
}
func (d *GooglePhoto) List(ctx context.Context, dir model.Obj, args model.ListArgs) ([]model.Obj, error) {
files, err := d.getFiles()
files, err := d.getFiles(dir.GetID())
if err != nil {
return nil, err
}
@ -58,7 +58,7 @@ func (d *GooglePhoto) List(ctx context.Context, dir model.Obj, args model.ListAr
//}
func (d *GooglePhoto) Link(ctx context.Context, file model.Obj, args model.LinkArgs) (*model.Link, error) {
f, err := d.getFile(file.GetID())
f, err := d.getMedia(file.GetID())
if err != nil {
return nil, err
}

View File

@ -10,6 +10,7 @@ type Addition struct {
RefreshToken string `json:"refresh_token" required:"true"`
ClientID string `json:"client_id" required:"true" default:"202264815644.apps.googleusercontent.com"`
ClientSecret string `json:"client_secret" required:"true" default:"X4Z3ca8xfWDb1Voo-F9a7ZxJ"`
ShowArchive bool `json:"show_archive"`
}
var config = driver.Config{

View File

@ -1,6 +1,7 @@
package google_photo
import (
"reflect"
"time"
"github.com/alist-org/alist/v3/internal/model"
@ -11,17 +12,21 @@ type TokenError struct {
ErrorDescription string `json:"error_description"`
}
type Files struct {
type Items struct {
NextPageToken string `json:"nextPageToken"`
MediaItems []MediaItem `json:"mediaItems"`
MediaItems []MediaItem `json:"mediaItems,omitempty"`
Albums []MediaItem `json:"albums,omitempty"`
SharedAlbums []MediaItem `json:"sharedAlbums,omitempty"`
}
type MediaItem struct {
Id string `json:"id"`
BaseURL string `json:"baseUrl"`
MimeType string `json:"mimeType"`
FileName string `json:"filename"`
MediaMetadata MediaMetadata `json:"mediaMetadata"`
Id string `json:"id"`
Title string `json:"title,omitempty"`
BaseURL string `json:"baseUrl,omitempty"`
CoverPhotoBaseUrl string `json:"coverPhotoBaseUrl,omitempty"`
MimeType string `json:"mimeType,omitempty"`
FileName string `json:"filename,omitempty"`
MediaMetadata MediaMetadata `json:"mediaMetadata,omitempty"`
}
type MediaMetadata struct {
@ -39,18 +44,29 @@ type Video struct {
}
func fileToObj(f MediaItem) *model.ObjThumb {
//size, _ := strconv.ParseInt(f.Size, 10, 64)
if !reflect.DeepEqual(f.MediaMetadata, MediaMetadata{}){
return &model.ObjThumb{
Object: model.Object{
ID: f.Id,
Name: f.FileName,
Size: 0,
Modified: f.MediaMetadata.CreationTime,
IsFolder: false,
},
Thumbnail: model.Thumbnail{
Thumbnail: f.BaseURL + "=w100-h100-c",
},
}
}
return &model.ObjThumb{
Object: model.Object{
ID: f.Id,
Name: f.FileName,
Name: f.Title,
Size: 0,
Modified: f.MediaMetadata.CreationTime,
IsFolder: false,
},
Thumbnail: model.Thumbnail{
Thumbnail: f.BaseURL + "=w100-h100-c",
Modified: time.Time{},
IsFolder: true,
},
Thumbnail: model.Thumbnail{},
}
}

View File

@ -10,6 +10,13 @@ import (
// do others that not defined in Driver interface
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
@ -34,6 +41,7 @@ func (d *GooglePhoto) refreshToken() error {
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)
}
@ -63,32 +71,83 @@ func (d *GooglePhoto) request(url string, method string, callback base.ReqCallba
return res.Body(), nil
}
func (d *GooglePhoto) getFiles() ([]MediaItem, error) {
pageToken := "first"
res := make([]MediaItem, 0)
for pageToken != "" {
if pageToken == "first" {
pageToken = ""
}
var resp Files
query := map[string]string{
"fields": "mediaItems(id,baseUrl,mimeType,mediaMetadata,filename),nextPageToken",
"pageSize": "100",
"pageToken": pageToken,
}
_, err := d.request("https://photoslibrary.googleapis.com/v1/mediaItems", http.MethodGet, func(req *resty.Request) {
req.SetQueryParams(query)
}, &resp, nil)
if err != nil {
return nil, err
}
pageToken = resp.NextPageToken
res = append(res, resp.MediaItems...)
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)
}
return res, nil
}
func (d *GooglePhoto) getFile(id string) (MediaItem, error) {
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{
@ -103,3 +162,25 @@ func (d *GooglePhoto) getFile(id string) (MediaItem, error) {
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
}