Implement sidecar video thumbnails and improved processing UI

- Implemented "sidecar" thumbnail logic: imports video thumbnails from Google Photos as hidden Drive files to display immediately while videos process.
- Updated MediaService to serve sidecar thumbnails via server-side Base64 encoding, bypassing CORS restrictions.
- Implemented lifecycle management: detects video processing completion to automatically cleanup sidecar files and fallback to native Drive thumbnails.
- Enhanced Media Manager UI: added processing warning banner and refined processing tile styling (centered, lighter overlay).
- Upgraded Drive API to v3 and improved file creation robustness with Advanced API fallbacks.
This commit is contained in:
Ben Miller
2025-12-30 23:41:59 -07:00
parent bade8a3020
commit 690f8c5c38
7 changed files with 358 additions and 95 deletions

View File

@ -43,23 +43,33 @@ export class MockDriveService implements IDriveService {
saveFile(blob: GoogleAppsScript.Base.Blob, folderId: string): GoogleAppsScript.Drive.File {
const id = `mock_file_${Date.now()}_${Math.floor(Math.random() * 1000)}`
const newFile = {
getId: () => id,
getName: () => blob.getName(),
getBlob: () => blob,
getUrl: () => `https://mock.drive/files/${blob.getName()}`,
getLastUpdated: () => new Date(),
getThumbnail: () => ({ getBytes: () => [] }),
getThumbnail: () => (blob as any).getThumbnail ? (blob as any).getThumbnail() : ({ getBytes: () => [] }),
getMimeType: () => (blob as any).getContentType ? (blob as any).getContentType() : "image/jpeg",
getDownloadUrl: () => `https://drive.google.com/uc?export=download&id=${id}`,
getSize: () => blob.getBytes ? blob.getBytes().length : 0,
getAppProperty: (key) => {
return (newFile as any)._properties?.[key]
}
getAppProperty: (key) => (newFile as any)._properties?.[key],
// Placeholder methods to be overridden safely
setDescription: null as any,
getDescription: null as any
} as unknown as GoogleAppsScript.Drive.File
// Initialize properties container
;(newFile as any)._properties = {}
// Initialize state
;(newFile as any)._properties = {};
;(newFile as any)._description = "";
// Attach methods safely
newFile.setDescription = (desc: string) => {
(newFile as any)._description = desc;
return newFile;
};
newFile.getDescription = () => (newFile as any)._description || "";
if (!this.files.has(folderId)) {
this.files.set(folderId, [])