Skip to content

Commit eb1292f

Browse files
LittleJakexhofe
andauthored
feat: add Google Photos album id fetcher. (#154)
* feat: add Google Photos album id fetcher. * optimization --------- Co-authored-by: Andy Hsu <[email protected]>
1 parent 39160ea commit eb1292f

File tree

4 files changed

+188
-1
lines changed

4 files changed

+188
-1
lines changed
Lines changed: 166 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,166 @@
1+
<script lang="ts" setup>
2+
import { NAlert, NSpace, NTable, NInput, NButton, NSelect, NThead, NTbody, NTh, NTd, NTr } from 'naive-ui';
3+
import { ref, reactive } from 'vue';
4+
5+
const url = new URL(window.location.href);
6+
7+
const data = reactive({
8+
client_id: "",
9+
client_secret: "",
10+
access_token: url.searchParams.get("access_token") || "",
11+
refresh_token: "",
12+
})
13+
14+
const way = ref<"access_token" | "refresh_token">("access_token")
15+
16+
interface Token {
17+
access_token: string;
18+
expires_in: number;
19+
refresh_token: string;
20+
scope: string;
21+
error: string;
22+
error_description: string;
23+
}
24+
25+
interface Album {
26+
albums: {
27+
id: string,
28+
title: string,
29+
productUrl: string,
30+
coverPhotoBaseUrl: string,
31+
coverPhotoMediaItemId: string,
32+
isWriteable: string,
33+
mediaItemsCount: string
34+
}[];
35+
nextPageToken: string;
36+
error: {
37+
code: number,
38+
message: string,
39+
status: string,
40+
};
41+
}
42+
43+
const token = ref<Token>();
44+
const album = ref<Album>();
45+
let albums = ref<Album['albums']>([]);
46+
47+
const getToken = async () => {
48+
const params = new URLSearchParams();
49+
params.append("client_id", data.client_id);
50+
params.append("client_secret", data.client_secret);
51+
params.append("grant_type", "refresh_token");
52+
params.append("refresh_token", data.refresh_token);
53+
54+
fetch("https://www.googleapis.com/oauth2/v4/token", {
55+
method: "POST",
56+
headers: {
57+
"Content-Type": "application/x-www-form-urlencoded",
58+
},
59+
body: params,
60+
})
61+
.then((resp) => resp.json())
62+
.then((res) => {
63+
console.log(res);
64+
token.value = res
65+
if (typeof (res.error) == 'undefined' || !res.error) {
66+
data.access_token = res.access_token
67+
if (typeof (res.access_token) != 'undefined' && res.access_token)
68+
getAlbum(null)
69+
}
70+
});
71+
};
72+
73+
const getAlbum = async (nextPageToken) => {
74+
if (nextPageToken == null)
75+
nextPageToken = ""
76+
77+
fetch(`https://photoslibrary.googleapis.com/v1/albums?pageToken=${nextPageToken}&pageSize=50`, {
78+
method: "GET",
79+
headers: {
80+
"Authorization": `Bearer ${data.access_token}`,
81+
},
82+
})
83+
.then((resp) => resp.json())
84+
.then((res) => {
85+
console.log(res);
86+
album.value = res;
87+
if (typeof (res.error) == 'undefined' || !res.error) {
88+
albums.value = albums.value.concat(res.albums)
89+
console.log(albums);
90+
if (typeof (res.nextPageToken) != 'undefined' && res.nextPageToken) {
91+
getAlbum(res.nextPageToken)
92+
}
93+
}
94+
});
95+
};
96+
97+
// auto get
98+
if (data.access_token) {
99+
getAlbum(null)
100+
}
101+
102+
function fetchAlbum() {
103+
albums.value = []
104+
if (way.value == 'refresh_token')
105+
getToken()
106+
else
107+
getAlbum(null)
108+
}
109+
110+
</script>
111+
112+
<template>
113+
<NSpace vertical size="large">
114+
<NSelect v-model:value="way" size="large" :options="[
115+
{ label: 'Access token', value: 'access_token' },
116+
{ label: 'Client & Refresh token', value: 'refresh_token' }
117+
]" />
118+
<NSpace v-if="way == 'refresh_token'" vertical size="large">
119+
<h4>client_id</h4>
120+
<NInput size="large" v-model:value="data.client_id" />
121+
<h4>client_secret</h4>
122+
<NInput size="large" v-model:value="data.client_secret" />
123+
<h4>refresh_token</h4>
124+
<NInput size="large" v-model:value="data.refresh_token" />
125+
</NSpace>
126+
<NSpace v-else vertical size="large">
127+
<h4>access_token</h4>
128+
<NInput size="large" v-model:value="data.access_token" />
129+
</NSpace>
130+
131+
<NButton size="large" type="primary" block @click="fetchAlbum">Fetch Album</NButton>
132+
<NAlert :title="token?.error" v-if="token?.error || token?.error_description" type="error">
133+
{{ token?.error_description }}
134+
</NAlert>
135+
<NAlert :title="album?.error.status" v-if="album?.error" type="error">
136+
{{ album?.error.message }}
137+
</NAlert>
138+
<h4>Albums</h4>
139+
<NTable size="large">
140+
<NThead>
141+
<NTr>
142+
<NTh>Album Title</NTh>
143+
<NTh>Album ID</NTh>
144+
</NTr>
145+
</NThead>
146+
<NTbody>
147+
<NTr v-for="(item, _) in albums">
148+
<NTd>{{ item.title }}</NTd>
149+
<NTd>{{ item.id }}</NTd>
150+
</NTr>
151+
</NTbody>
152+
</NTable>
153+
</NSpace>
154+
</template>
155+
156+
<style scoped>
157+
h4,
158+
h3 {
159+
margin: 0;
160+
}
161+
162+
td {
163+
word-break: break-all;
164+
word-wrap: break-word;
165+
}
166+
</style>

docs/.vuepress/components/google/Callback.vue

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
<script lang="ts" setup>
2-
import { NAlert, NSpace, NSpin, NInput } from 'naive-ui';
2+
import { NAlert, NSpace, NSpin, NInput, NButton } from 'naive-ui';
33
import { ref } from 'vue';
44
55
const url = new URL(window.location.href);
@@ -46,6 +46,10 @@ if (code && !error) {
4646
getToken();
4747
}
4848
49+
function getAlbumID() {
50+
window.open(`/tool/google/album?access_token=${token.value?.access_token}`, "_blank");
51+
}
52+
4953
</script>
5054

5155
<template>
@@ -66,6 +70,7 @@ if (code && !error) {
6670
<NAlert v-else-if="token?.access_token" title="Web client" type="warning">
6771
The refresh_token is only returned once if you use a web client.
6872
</NAlert>
73+
<NButton v-if="token?.access_token" @click="getAlbumID" block type="primary">Get Album ID</NButton>
6974
</NSpace>
7075
</NSpace>
7176
</template>

docs/.vuepress/config.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -117,5 +117,9 @@ export default defineUserConfig({
117117
__dirname,
118118
"./components/google/Callback.vue"
119119
),
120+
"@Google/Album": path.resolve(
121+
__dirname,
122+
"./components/google/Album.vue"
123+
),
120124
},
121125
});

docs/tool/google/album.md

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
---
2+
title: "Get Google Photos Album ID"
3+
toc: false
4+
---
5+
6+
<NaiveClient>
7+
<Album />
8+
</NaiveClient>
9+
10+
<script setup lang="ts">
11+
import Album from "@Google/Album";
12+
</script>

0 commit comments

Comments
 (0)