feat: Add custom video thumbnails for Drive uploads
- Implemented custom thumbnail injection in GASDriveService.getResumableUploadUrl. - Fetches thumbnails from Google Photos using w320 size to avoid API limits. - Added strict < 2MB size check for thumbnails. - Updated mediaHandlers and MediaManager to pass sourceUrl to the backend. - This allows Drive to display a visual cue immediately for video files still processing.
This commit is contained in:
@ -1364,7 +1364,7 @@
|
||||
|
||||
})
|
||||
.withFailureHandler(e => ui.logStatus('error', `Ticket failed: ${e.message}`, 'error'))
|
||||
.getUploadUrl(state.sku, filename, mimeType);
|
||||
.getUploadUrl(state.sku, filename, mimeType, fetchUrl);
|
||||
})
|
||||
.withFailureHandler(e => {
|
||||
ui.logStatus('error', `Cannot transfer ${filename}: ${e.message}`, 'error');
|
||||
|
||||
@ -128,7 +128,7 @@ export function linkDriveFileToShopifyMedia(sku: string, driveId: string, shopif
|
||||
}
|
||||
|
||||
// NEW: Resumable Upload Ticket
|
||||
export function getUploadUrl(sku: string, filename: string, mimeType: string) {
|
||||
export function getUploadUrl(sku: string, filename: string, mimeType: string, sourceUrl?: string) {
|
||||
const config = new Config()
|
||||
const driveService = new GASDriveService()
|
||||
|
||||
@ -136,7 +136,7 @@ export function getUploadUrl(sku: string, filename: string, mimeType: string) {
|
||||
const folder = driveService.getOrCreateFolder(sku, config.productPhotosFolderId)
|
||||
|
||||
// Generate Ticket
|
||||
return driveService.getResumableUploadUrl(filename, mimeType, folder.getId())
|
||||
return driveService.getResumableUploadUrl(filename, mimeType, folder.getId(), sourceUrl)
|
||||
}
|
||||
|
||||
// Deprecated (but kept for fallback/legacy small files if needed)
|
||||
|
||||
@ -100,16 +100,59 @@ export class GASDriveService implements IDriveService {
|
||||
}
|
||||
}
|
||||
|
||||
getResumableUploadUrl(filename: string, mimeType: string, folderId: string): string {
|
||||
getResumableUploadUrl(filename: string, mimeType: string, folderId: string, sourceUrl?: string): string {
|
||||
const token = ScriptApp.getOAuthToken();
|
||||
|
||||
// Metadata for the file to be created
|
||||
const metadata = {
|
||||
const metadata: any = {
|
||||
name: filename,
|
||||
mimeType: mimeType,
|
||||
parents: [folderId]
|
||||
};
|
||||
|
||||
// feature: video-thumbnails-for-processing
|
||||
// If this is a video from Google Photos, fetch a thumbnail and set as contentHint.
|
||||
if (sourceUrl && sourceUrl.includes('googleusercontent.com') && mimeType.startsWith('video/')) {
|
||||
try {
|
||||
console.log(`[GASDriveService] Fetching thumbnail for ${filename}...`);
|
||||
// =w800-h600 gives a decent sized jpeg thumbnail
|
||||
// Use same auth token as we use for the video fetch
|
||||
let thumbUrl = sourceUrl;
|
||||
if (!thumbUrl.includes('=')) {
|
||||
thumbUrl += '=w320-h320';
|
||||
} else {
|
||||
thumbUrl = thumbUrl.replace(/=.*$/, '') + '=w320-h320';
|
||||
}
|
||||
|
||||
const thumbResp = UrlFetchApp.fetch(thumbUrl, {
|
||||
headers: { Authorization: `Bearer ${token}` },
|
||||
muteHttpExceptions: true
|
||||
});
|
||||
|
||||
if (thumbResp.getResponseCode() === 200) {
|
||||
const thumbBlob = thumbResp.getBlob();
|
||||
const base64Thumb = Utilities.base64EncodeWebSafe(thumbBlob.getBytes());
|
||||
|
||||
// Drive API Limit check (2MB)
|
||||
if (base64Thumb.length < 2 * 1024 * 1024) {
|
||||
metadata.contentHints = {
|
||||
thumbnail: {
|
||||
image: base64Thumb,
|
||||
mimeType: 'image/jpeg'
|
||||
}
|
||||
};
|
||||
console.log(`[GASDriveService] Custom thumbnail injected (${base64Thumb.length} chars).`);
|
||||
} else {
|
||||
console.warn(`[GASDriveService] Thumbnail too large (${base64Thumb.length} chars). Skipping injection.`);
|
||||
}
|
||||
} else {
|
||||
console.warn(`[GASDriveService] Thumbnail fetch failed: ${thumbResp.getResponseCode()}`);
|
||||
}
|
||||
} catch (e) {
|
||||
console.warn(`[GASDriveService] Thumbnail generation failed: ${e.message}`);
|
||||
}
|
||||
}
|
||||
|
||||
const params = {
|
||||
method: 'post' as const,
|
||||
contentType: 'application/json',
|
||||
|
||||
Reference in New Issue
Block a user