← back to AbramsOS
lib/drive-fetcher.js
57 lines
// Google Drive fetcher. Walks the user's Drive for receipt-shaped files
// (PDFs, JPGs, PNGs whose name suggests "receipt", "invoice", "order").
// Returns metadata + file content stream; the caller persists.
//
// Uses the same OAuth client (refresh token shared with Gmail since it's the
// same Google account, drive.readonly scope was added to lib/google-oauth.js).
const { google } = require('googleapis');
const { clientFor } = require('./google-oauth');
const RECEIPT_NAME_QUERY = `(name contains 'receipt' or name contains 'invoice' or name contains 'order' or name contains 'confirmation')`;
const MIME_QUERY = `(mimeType = 'application/pdf' or mimeType contains 'image/')`;
const RECENT_QUERY = `modifiedTime > '${new Date(Date.now() - 90 * 24 * 60 * 60 * 1000).toISOString()}'`;
function driveClient(refreshToken) {
return google.drive({ version: 'v3', auth: clientFor(refreshToken) });
}
async function listReceiptFiles(refreshToken, { max = 100 } = {}) {
const drive = driveClient(refreshToken);
const out = [];
let pageToken;
do {
const resp = await drive.files.list({
q: `${RECEIPT_NAME_QUERY} and ${MIME_QUERY} and ${RECENT_QUERY} and trashed = false`,
fields: 'nextPageToken, files(id, name, mimeType, size, modifiedTime, webViewLink, webContentLink, md5Checksum)',
pageSize: Math.min(100, max - out.length),
pageToken,
orderBy: 'modifiedTime desc',
});
for (const f of resp.data.files || []) out.push(f);
pageToken = resp.data.nextPageToken;
} while (pageToken && out.length < max);
return out;
}
/**
* Returns an async stream of bytes for a Drive file.
* Caller handles writing to disk / hashing.
*/
async function downloadFile(refreshToken, fileId) {
const drive = driveClient(refreshToken);
const resp = await drive.files.get({ fileId, alt: 'media' }, { responseType: 'stream' });
return resp.data;
}
async function fileMetadata(refreshToken, fileId) {
const drive = driveClient(refreshToken);
const resp = await drive.files.get({
fileId,
fields: 'id, name, mimeType, size, modifiedTime, webViewLink, md5Checksum',
});
return resp.data;
}
module.exports = { listReceiptFiles, downloadFile, fileMetadata };