Skip to content

Commit 1ed6d14

Browse files
authored
Merge pull request #2 from siriusnottin/develop
feat: new MediaType support
2 parents 314dbe4 + 67c5228 commit 1ed6d14

File tree

4 files changed

+175
-137
lines changed

4 files changed

+175
-137
lines changed

helpers.ts

+45
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
import * as coda from "@codahq/packs-sdk";
2+
3+
export const ApiUrl = "https://photoslibrary.googleapis.com/v1";
4+
5+
export async function getConnectionName(context: coda.ExecutionContext) {
6+
let request: coda.FetchRequest = {
7+
method: "GET",
8+
url: "https://www.googleapis.com/oauth2/v1/userinfo",
9+
headers: {
10+
"Content-Type": "application/json",
11+
},
12+
};
13+
let userResponse = await context.fetcher.fetch(request);
14+
let user = userResponse.body;
15+
return user.name as string;
16+
}
17+
18+
export const MediasContentCategoriesList = {
19+
Animals: "ANIMALS",
20+
Fashion: "FASHION",
21+
Landmarks: "LANDMARKS",
22+
Receipts: "RECEIPTS",
23+
Weddings: "WEDDINGS",
24+
Arts: "ARTS",
25+
Flowers: "FLOWERS",
26+
Landscapes: "LANDSCAPES",
27+
Screenshots: "SCREENSHOTS",
28+
Whiteboards: "WHITEBOARDS",
29+
Birthdays: "BIRTHDAYS",
30+
Food: "FOOD",
31+
Night: "NIGHT",
32+
Selfies: "SELFIES",
33+
Cityscapes: "CITYSCAPES",
34+
Gardens: "GARDENS",
35+
People: "PEOPLE",
36+
Sport: "SPORT",
37+
Crafts: "CRAFTS",
38+
Holidays: "HOLIDAYS",
39+
Performances: "PERFORMANCES",
40+
Travel: "TRAVEL",
41+
Documents: "DOCUMENTS",
42+
Houses: "HOUSES",
43+
Pets: "PETS",
44+
Utility: "UTILITY"
45+
}

pack.ts

+30-137
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,9 @@
11
import * as coda from "@codahq/packs-sdk";
2-
export const pack = coda.newPack();
2+
import * as helpers from "./helpers";
3+
import * as params from "./params";
4+
import * as schemas from "./schemas";
35

4-
const ApiBaseUrl = "https://photoslibrary.googleapis.com/v1";
6+
export const pack = coda.newPack();
57

68
pack.addNetworkDomain("googleapis.com");
79

@@ -17,112 +19,24 @@ pack.setUserAuthentication({
1719
access_type: "offline",
1820
prompt: "consent",
1921
},
20-
21-
// Determines the display name of the connected account.
22-
getConnectionName: async function (context) {
23-
let response = await context.fetcher.fetch({
24-
method: "GET",
25-
url: "https://www.googleapis.com/oauth2/v1/userinfo",
26-
});
27-
let user = response.body;
28-
return user.name;
29-
},
30-
});
31-
32-
const MediaSchema = coda.makeObjectSchema({
33-
properties: {
34-
mediaId: {
35-
type: coda.ValueType.String,
36-
fromKey: "id",
37-
required: true
38-
},
39-
filename: { type: coda.ValueType.String, required: true },
40-
description: { type: coda.ValueType.String },
41-
creationTime: {
42-
type: coda.ValueType.String,
43-
codaType: coda.ValueHintType.DateTime
44-
},
45-
width: { type: coda.ValueType.Number },
46-
height: { type: coda.ValueType.Number },
47-
image: {
48-
type: coda.ValueType.String,
49-
codaType: coda.ValueHintType.ImageReference,
50-
},
51-
url: {
52-
type: coda.ValueType.String,
53-
description: "Google Photos URL for the media.",
54-
codaType: coda.ValueHintType.Url,
55-
fromKey: "productUrl",
56-
},
57-
},
58-
displayProperty: "filename",
59-
idProperty: "mediaId",
60-
featuredProperties: [
61-
"image"
62-
],
63-
});
64-
65-
const MediaDateRangeParam = coda.makeParameter({
66-
type: coda.ParameterType.DateArray,
67-
name: "dateRange",
68-
description: "The date range over which data should be fetched.",
69-
suggestedValue: coda.PrecannedDateRange.LastWeek,
70-
});
71-
72-
const MediasContentCategoriesList = {
73-
Animals: "ANIMALS",
74-
Fashion: "FASHION",
75-
Landmarks: "LANDMARKS",
76-
Receipts: "RECEIPTS",
77-
Weddings: "WEDDINGS",
78-
Arts: "ARTS",
79-
Flowers: "FLOWERS",
80-
Landscapes: "LANDSCAPES",
81-
Screenshots: "SCREENSHOTS",
82-
Whiteboards: "WHITEBOARDS",
83-
Birthdays: "BIRTHDAYS",
84-
Food: "FOOD",
85-
Night: "NIGHT",
86-
Selfies: "SELFIES",
87-
Cityscapes: "CITYSCAPES",
88-
Gardens: "GARDENS",
89-
People: "PEOPLE",
90-
Sport: "SPORT",
91-
Crafts: "CRAFTS",
92-
Holidays: "HOLIDAYS",
93-
Performances: "PERFORMANCES",
94-
Travel: "TRAVEL",
95-
Documents: "DOCUMENTS",
96-
Houses: "HOUSES",
97-
Pets: "PETS",
98-
Utility: "UTILITY"
99-
}
100-
101-
const MediaCategoriesParam = coda.makeParameter({
102-
type: coda.ParameterType.StringArray,
103-
name: "categories",
104-
description: "Filter by medias categories.",
105-
optional: true,
106-
autocomplete: Object.keys(MediasContentCategoriesList)
107-
});
108-
109-
const MediaFavoritesParam = coda.makeParameter({
110-
type: coda.ParameterType.Boolean,
111-
name: "favorite",
112-
description: "Filter by favorites medias.",
113-
optional: true,
22+
getConnectionName: helpers.getConnectionName,
11423
});
11524

11625
pack.addSyncTable({
11726
name: "Medias",
118-
schema: MediaSchema,
27+
schema: schemas.MediaSchema,
11928
identityName: "Media",
12029
formula: {
12130
name: "SyncMedias",
12231
description: "Sync medias from the user's library.",
123-
parameters: [MediaDateRangeParam, MediaCategoriesParam, MediaFavoritesParam],
124-
execute: async function ([dateRange, categories, favorite], context) {
125-
let url = `${ApiBaseUrl}/mediaItems:search`;
32+
parameters: [
33+
params.MediaDateRangeParam,
34+
params.MediaTypeParam,
35+
params.MediaCategoriesIncludeParam,
36+
params.MediaFavoritesParam
37+
],
38+
execute: async function ([dateRange, mediaType, categories, favorite], context) {
39+
let url = `${helpers.ApiUrl}/mediaItems:search`;
12640

12741
function formatDate(date: Date, dateFormatter: Intl.DateTimeFormat) {
12842
const dateParts = dateFormatter.formatToParts(date);
@@ -163,7 +77,7 @@ pack.addSyncTable({
16377
includedContentCategories: string[],
16478
};
16579
};
166-
pageToken?: string;
80+
pageToken?: undefined | string;
16781
};
16882

16983
let payload: RequestPayload = {
@@ -176,7 +90,7 @@ pack.addSyncTable({
17690
}]
17791
},
17892
featureFilter: (favorite) ? { includedFeatures: ["FAVORITES"] } : undefined,
179-
contentFilter: (categories) ? { includedContentCategories: categories.map(category => (MediasContentCategoriesList[category])) } : undefined,
93+
contentFilter: (categories) ? { includedContentCategories: categories.map(category => (helpers.MediasContentCategoriesList[category])) } : undefined,
18094
},
18195
pageToken: (context.sync.continuation?.nextPageToken) ? context.sync.continuation.nextPageToken : undefined,
18296
}
@@ -191,10 +105,20 @@ pack.addSyncTable({
191105
let items = response.body.mediaItems;
192106
if (items && items.length > 0) {
193107
for (let item of items) {
108+
// the api returns item.mediaMetadata.photo and item.mediaMetadata.video, we want to have a single mediaType property.
109+
item.mediaType = (item.mediaMetadata.photo) ? "Photo" : "Video";
194110
item.creationTime = item.mediaMetadata.creationTime
195111
item.width = item.mediaMetadata.width
196112
item.height = item.mediaMetadata.height
197-
item.image = item.baseUrl + "=w2048-h1024"
113+
};
114+
};
115+
if (mediaType) {
116+
items = items.filter(item => (item.mediaType === mediaType));
117+
}
118+
if (items && items.length > 0) {
119+
for (let item of items) {
120+
// We get the image only after we have filtered the items since it can become quite costly in ressources.
121+
item.image = item.baseUrl + "=w2048-h1024"//TODO: add parameter for image sizes.
198122
};
199123
};
200124
let continuation;
@@ -211,47 +135,16 @@ pack.addSyncTable({
211135
},
212136
});
213137

214-
const MediaReferenceSchema = coda.makeReferenceSchemaFromObjectSchema(MediaSchema, "Media");
215-
216-
const AlbumSchema = coda.makeObjectSchema({
217-
properties: {
218-
albumId: {
219-
type: coda.ValueType.String,
220-
fromKey: "id",
221-
},
222-
title: { type: coda.ValueType.String },
223-
// medias: {
224-
// type: coda.ValueType.Array,
225-
// items: MediaReferenceSchema
226-
// },
227-
url: {
228-
type: coda.ValueType.String,
229-
description: "Google Photos URL for the album.",
230-
codaType: coda.ValueHintType.Url,
231-
fromKey: "productUrl",
232-
},
233-
coverPhoto: {
234-
type: coda.ValueType.String,
235-
codaType: coda.ValueHintType.ImageReference,
236-
},
237-
},
238-
displayProperty: "title",
239-
idProperty: "albumId",
240-
featuredProperties: [
241-
"coverPhoto"
242-
]
243-
});
244-
245138
pack.addSyncTable({
246139
name: "Albums",
247-
schema: AlbumSchema,
140+
schema: schemas.AlbumSchema,
248141
identityName: "Album",
249142
formula: {
250143
name: "SyncAlbums",
251144
description: "Sync all albums.",
252145
parameters: [],
253146
execute: async function ([], context) {
254-
let url = `${ApiBaseUrl}/albums`;
147+
let url = `${helpers.ApiUrl}/albums`;
255148

256149
if (context.sync.continuation) {
257150
url = coda.withQueryParams(url, { pageToken: context.sync.continuation })
@@ -270,7 +163,7 @@ pack.addSyncTable({
270163
const Albums = await AlbumsResponse.body.albums;
271164
for (const album of Albums) {
272165
// we want to search for all medias in the current album.
273-
// let url = coda.withQueryParams(`${ApiBaseUrl}/mediaItems:search`, { pageSize: 5 });
166+
// let url = coda.withQueryParams(`${helpers.ApiUrl}/mediaItems:search`, { pageSize: 5 });
274167
// let body = { albumId: album.id };
275168
// let mediaItemsInAlbum = [];
276169
// let mediaItemsNextPageToken;

params.ts

+34
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
import * as coda from "@codahq/packs-sdk";
2+
import * as helpers from "./helpers";
3+
import { MediasContentCategoriesList } from "./helpers";
4+
5+
export const MediaDateRangeParam = coda.makeParameter({
6+
type: coda.ParameterType.DateArray,
7+
name: "dateRange",
8+
description: "The date range over which data should be fetched.",
9+
suggestedValue: coda.PrecannedDateRange.LastWeek,
10+
});
11+
12+
export const MediaTypeParam = coda.makeParameter({
13+
type: coda.ParameterType.String,
14+
name: "mediaType",
15+
description: "The type of media to fetch.",
16+
autocomplete: ["Photo", "Video"],
17+
optional: true,
18+
});
19+
20+
export const MediaCategoriesIncludeParam = coda.makeParameter({
21+
type: coda.ParameterType.StringArray,
22+
name: "categories",
23+
description: "Filter by medias categories.",
24+
optional: true,
25+
autocomplete: Object.keys(MediasContentCategoriesList)
26+
});
27+
28+
export const MediaFavoritesParam = coda.makeParameter({
29+
type: coda.ParameterType.Boolean,
30+
name: "favorite",
31+
description: "Filter by favorites medias.",
32+
optional: true,
33+
});
34+

schemas.ts

+66
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,66 @@
1+
import * as coda from "@codahq/packs-sdk";
2+
3+
export const MediaSchema = coda.makeObjectSchema({
4+
properties: {
5+
mediaId: {
6+
type: coda.ValueType.String,
7+
fromKey: "id",
8+
required: true
9+
},
10+
filename: { type: coda.ValueType.String, required: true },
11+
mediaType: { type: coda.ValueType.String },
12+
description: { type: coda.ValueType.String },
13+
creationTime: {
14+
type: coda.ValueType.String,
15+
codaType: coda.ValueHintType.DateTime
16+
},
17+
width: { type: coda.ValueType.Number },
18+
height: { type: coda.ValueType.Number },
19+
image: {
20+
type: coda.ValueType.String,
21+
codaType: coda.ValueHintType.ImageAttachment,
22+
},
23+
url: {
24+
type: coda.ValueType.String,
25+
description: "Google Photos URL for the media.",
26+
codaType: coda.ValueHintType.Url,
27+
fromKey: "productUrl",
28+
},
29+
},
30+
displayProperty: "filename",
31+
idProperty: "mediaId",
32+
featuredProperties: [
33+
"image"
34+
],
35+
});
36+
37+
export const MediaReferenceSchema = coda.makeReferenceSchemaFromObjectSchema(MediaSchema, "Media");
38+
39+
export const AlbumSchema = coda.makeObjectSchema({
40+
properties: {
41+
albumId: {
42+
type: coda.ValueType.String,
43+
fromKey: "id",
44+
},
45+
title: { type: coda.ValueType.String },
46+
medias: {
47+
type: coda.ValueType.Array,
48+
items: MediaReferenceSchema
49+
},
50+
url: {
51+
type: coda.ValueType.String,
52+
description: "Google Photos URL for the album.",
53+
codaType: coda.ValueHintType.Url,
54+
fromKey: "productUrl",
55+
},
56+
coverPhoto: {
57+
type: coda.ValueType.String,
58+
codaType: coda.ValueHintType.ImageAttachment,
59+
},
60+
},
61+
displayProperty: "title",
62+
idProperty: "albumId",
63+
featuredProperties: [
64+
"coverPhoto"
65+
]
66+
});

0 commit comments

Comments
 (0)