Compare commits

...

2 Commits

Author SHA1 Message Date
f25fb359e8 Fix Shopify video previews and various improvements
- Ensure Shopify video sync updates Media Manager with active video previews
- Fix "Image load failed" error for video icons by using Base64 SVG
- Resolve Drive picker origin error by using google.script.host.origin
- Fix Drive video playback issues by using Drive iframe player
- Add `test:log` script to package.json for full output logging in Windows
- Update .gitignore to exclude coverage, test_output.txt, and .agent/
- Remove test_output.txt from git tracking
2025-12-31 01:10:18 -07:00
64ab548593 Fix Shopify video preview propagation on save
Updates logic to detect processing state (including READY-but-no-sources race condition) and propagates contentUrl updates to the frontend immediately.
2025-12-31 01:08:12 -07:00
8 changed files with 53 additions and 2 deletions

2
.gitignore vendored
View File

@ -4,3 +4,5 @@ desktop.ini
.continue/** .continue/**
.clasp.json .clasp.json
coverage/ coverage/
test_output.txt
.agent/

View File

@ -46,3 +46,6 @@ This project (`product_inventory`) integrates Google Sheets with Shopify. It ser
- **Client-Side Syntax**: - **Client-Side Syntax**:
- **ES5 ONLY**: Do not use `class` in client-side HTML files. The Apps Script sanitizer often fails to parse them. Use `function` constructors. - **ES5 ONLY**: Do not use `class` in client-side HTML files. The Apps Script sanitizer often fails to parse them. Use `function` constructors.
## Troubleshooting
- **Test Output**: When running tests, use `npm run test:log` to capture full output to `test_output.txt`. This avoids terminal truncation and allows agents to read the full results without manual redirection.

View File

@ -9,6 +9,7 @@
"build": "webpack --mode production", "build": "webpack --mode production",
"deploy": "clasp push", "deploy": "clasp push",
"test": "jest", "test": "jest",
"test:log": "jest > test_output.txt 2>&1",
"prepare": "husky" "prepare": "husky"
}, },
"devDependencies": { "devDependencies": {

View File

@ -464,7 +464,7 @@
style="display:none; background-color:#fffbeb; color:#92400e; padding:12px; border-radius:8px; margin: 0 16px 12px 16px; font-size:13px; border:1px solid #fcd34d; align-items:flex-start; gap:8px;"> style="display:none; background-color:#fffbeb; color:#92400e; padding:12px; border-radius:8px; margin: 0 16px 12px 16px; font-size:13px; border:1px solid #fcd34d; align-items:flex-start; gap:8px;">
<span style="font-size:16px; line-height:1;"></span> <span style="font-size:16px; line-height:1;"></span>
<div> <div>
Some videos are still being transcoded by Drive. The video preview might not work yet, but they can still be saved, Some videos are still being processed. The video preview might not work yet, but they can still be saved,
reordered, or deleted. reordered, or deleted.
</div> </div>
</div> </div>
@ -1516,6 +1516,8 @@
console.log("[MediaManager] Processing complete for " + item.filename); console.log("[MediaManager] Processing complete for " + item.filename);
item.isProcessing = false; item.isProcessing = false;
item.thumbnail = newItem.thumbnail; item.thumbnail = newItem.thumbnail;
item.contentUrl = newItem.contentUrl; // Propagate URL
item.source = newItem.source; // Propagate source update (synced)
changed = true; changed = true;
} }
} }

View File

@ -304,4 +304,29 @@ describe("MediaService Robust Sync", () => {
expect(item.isProcessing).toBe(true) expect(item.isProcessing).toBe(true)
expect(item.thumbnail).toContain("data:image/svg+xml;base64") expect(item.thumbnail).toContain("data:image/svg+xml;base64")
}) })
test("Processing: Marks item as processing if Shopify status is PROCESSING", () => {
const folder = driveService.getOrCreateFolder("SKU_SHOP_PROCESS", "root")
// Drive File
const blob = { getName: () => "vid.mp4", getBytes: () => [], getMimeType: () => "video/mp4", getThumbnail: () => ({ getBytes: () => [] }) } as any
const f = driveService.saveFile(blob, folder.getId())
driveService.updateFileProperties(f.getId(), { shopify_media_id: "gid://shopify/Media/Proc1" })
// Shopify Media (Processing)
shopifyService.getProductMedia = jest.fn().mockReturnValue([
{
id: "gid://shopify/Media/Proc1",
filename: "vid.mp4",
mediaContentType: "VIDEO",
status: "PROCESSING",
preview: { image: { originalSrc: null } } // Preview might be missing during processing
}
])
const state = mediaService.getUnifiedMediaState("SKU_SHOP_PROCESS", "pid")
const item = state.find(s => s.id === f.getId())
expect(item.isProcessing).toBe(true)
})
}) })

View File

@ -106,6 +106,8 @@ export class MediaService {
if (props['custom_thumbnail_id']) customThumbnailId = props['custom_thumbnail_id']; if (props['custom_thumbnail_id']) customThumbnailId = props['custom_thumbnail_id'];
if (props['parent_video_id']) parentVideoId = props['parent_video_id']; if (props['parent_video_id']) parentVideoId = props['parent_video_id'];
console.log(`[DEBUG] File ${f.getName()} Props:`, JSON.stringify(props));
} catch (e) { } catch (e) {
console.warn(`Failed to get properties for ${f.getName()}`) console.warn(`Failed to get properties for ${f.getName()}`)
} }
@ -239,6 +241,21 @@ export class MediaService {
console.log(`[MediaService] Using Sidecar Thumbnail for ${d.file.getName()}`); console.log(`[MediaService] Using Sidecar Thumbnail for ${d.file.getName()}`);
thumbnail = sidecarThumbMap.get(d.file.getId()) || ""; thumbnail = sidecarThumbMap.get(d.file.getId()) || "";
isProcessing = true; // SHOW HOURGLASS (Request #3) isProcessing = true; // SHOW HOURGLASS (Request #3)
} else if (match && (
match.status === 'PROCESSING' ||
match.status === 'UPLOADED' ||
(match.mediaContentType === 'VIDEO' && (!match.sources || match.sources.length === 0) && match.status !== 'FAILED')
)) {
// Shopify Processing (Explicit Status OR Ready-but-missing-sources)
console.log(`[MediaService] Shopify Media is Processing: ${d.file.getName()} (Status: ${match.status}, Sources: ${match.sources ? match.sources.length : 0})`);
isProcessing = true;
// Use Drive thumb as fallback if Shopify preview not ready
if (!thumbnail) {
try {
const nativeThumb = `data:image/jpeg;base64,${Utilities.base64Encode(d.file.getThumbnail().getBytes())}`;
if (nativeThumb.length > 100) thumbnail = nativeThumb;
} catch(e) {}
}
} else { } else {
// 2. Native / Fallback // 2. Native / Fallback
try { try {

View File

@ -73,6 +73,7 @@ export class ShopifyMediaService implements IShopifyMediaService {
id id
alt alt
mediaContentType mediaContentType
status
preview { preview {
image { image {
originalSrc originalSrc

Binary file not shown.