Skip to content

Instantly share code, notes, and snippets.

@camilomontoyau
Last active February 15, 2025 14:27
Show Gist options
  • Select an option

  • Save camilomontoyau/0458a683b58916fb2e9da5afaf7e7101 to your computer and use it in GitHub Desktop.

Select an option

Save camilomontoyau/0458a683b58916fb2e9da5afaf7e7101 to your computer and use it in GitHub Desktop.
const { google } = require('googleapis');
const { authenticate } = require('@google-cloud/local-auth');
const fs = require('fs').promises;
const oldFs = require('fs');
const path = require('path');
const process = require('process');
const SCOPES = ['https://www.googleapis.com/auth/photoslibrary.readonly'];
const TOKEN_PATH = path.join(process.cwd(), 'token.json');
const CREDENTIALS_PATH = path.join(process.cwd(), 'credentials.json');
async function loadSavedCredentialsIfExist() {
try {
const content = await fs.readFile(TOKEN_PATH);
const credentials = JSON.parse(content);
return google.auth.fromJSON(credentials);
} catch {
return null;
}
}
async function saveCredentials(client) {
const content = await fs.readFile(CREDENTIALS_PATH);
const keys = JSON.parse(content);
const key = keys.installed || keys.web;
const payload = JSON.stringify({
type: 'authorized_user',
client_id: key.client_id,
client_secret: key.client_secret,
refresh_token: client.credentials.refresh_token,
});
await fs.writeFile(TOKEN_PATH, payload);
}
async function authorize() {
let client = await loadSavedCredentialsIfExist();
if (client) return client;
client = await authenticate({
scopes: SCOPES,
keyfilePath: CREDENTIALS_PATH,
});
if (client.credentials) {
await saveCredentials(client);
}
return client;
}
async function listAllMediaItems(auth) {
let allItems = [];
let pageToken = null;
do {
const url = pageToken
? `https://photoslibrary.googleapis.com/v1/mediaItems?pageSize=100&pageToken=${pageToken}`
: 'https://photoslibrary.googleapis.com/v1/mediaItems?pageSize=100';
console.log(`Fetching media items from: ${url}`);
try {
const res = await auth.request({ url });
const items = res.data.mediaItems || [];
allItems = allItems.concat(items);
pageToken = res.data.nextPageToken;
} catch (err) {
console.log('Error fetching media items:', err);
// throw err;
}
// break;
} while (pageToken);
console.log(`Total media items: ${allItems.length}`);
return allItems;
}
async function downloadPhotos() {
try {
const auth = await authorize();
const mediaItems = await listAllMediaItems(auth);
console.log('mediaItems: =================');
console.log(JSON.stringify(mediaItems, null, 2));
console.log('=================');
if (!mediaItems.length) {
console.log('No photos to download.');
return;
}
const downloadDir = path.join(process.cwd(), 'downloads');
try {
await fs.mkdir(downloadDir);
} catch {}
for (const item of mediaItems) {
const url = `${item.baseUrl}=d`;
const filePath = path.join(downloadDir, item.filename || `${item.id}.jpg`);
console.log(`Downloading ${item.filename || item.id} from ${url}`);
// check if file already exists
try {
if(oldFs.existsSync(filePath)) {
console.log(`File already exists: ${item.filename || item.id}`);
continue;
}
} catch (error) {
console.log(`Failed to access ${item.filename || item.id}:`, error);
continue;
}
try {
const response = await fetch(url);
if (!response.ok) {
throw new Error(`Failed to download ${item.filename || item.id}: ${response.statusText}`);
}
const buffer = await response.arrayBuffer();
await fs.writeFile(filePath, Buffer.from(buffer));
console.log(`Downloaded ${item.filename || item.id}`);
} catch (error) {
console.log(`Failed to download ${item.filename || item.id}:`, error);
}
}
console.log('Download complete.!!!!!!!!!');
} catch (error) {
console.log('Error downloading photos:', error);
}
}
downloadPhotos().catch(console.log);
{
"name": "download-photos-from-google",
"version": "1.0.0",
"description": "",
"main": "download.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"keywords": [],
"author": "",
"license": "ISC",
"dependencies": {
"@google-cloud/local-auth": "^3.0.1",
"google-auth-library": "^9.15.1",
"googleapis": "^144.0.0",
"node-fetch": "^3.3.2",
"readline": "^1.3.0"
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment