fix: workspace-aware media resolution + production-ready logging
- load_podcast_image_bytes now accepts user_id for workspace-aware resolution - Video and avatar handlers pass user_id to image loading - Strip JWT tokens from console logs (dev-only verbose logging) - Guard debug logs behind NODE_ENV===development in SceneCard, useRenderQueue, SubscriptionContext, mediaCache - Add devLogger utility
This commit is contained in:
@@ -224,8 +224,10 @@ apiClient.interceptors.request.use(
|
||||
if (token) {
|
||||
config.headers = config.headers || {};
|
||||
(config.headers as any)['Authorization'] = `Bearer ${token}`;
|
||||
const safeUrlWithToken = sanitizeUrlForLogging(config.url);
|
||||
console.log(`[apiClient] ✅ Auth token attached for request to ${safeUrlWithToken}`);
|
||||
if (process.env.NODE_ENV === 'development') {
|
||||
const safeUrlWithToken = sanitizeUrlForLogging(config.url);
|
||||
console.log(`[apiClient] ✅ Auth token attached for request to ${safeUrlWithToken}`);
|
||||
}
|
||||
} else {
|
||||
// Token getter returned null - reject request to prevent 401 errors
|
||||
// ProtectedRoute should ensure user is authenticated before components render
|
||||
|
||||
@@ -140,7 +140,7 @@ export const SceneCard: React.FC<SceneCardProps> = ({
|
||||
// Check cache first with scene context
|
||||
const cachedUrl = getCachedMedia(imageUrl, scene.id);
|
||||
if (cachedUrl) {
|
||||
console.log('[SceneCard] Using cached image:', imageUrl, `(scene: ${scene.id})`);
|
||||
if (process.env.NODE_ENV === 'development') console.log('[SceneCard] Using cached image:', imageUrl, `(scene: ${scene.id})`);
|
||||
setImageBlobUrl(cachedUrl);
|
||||
setImageLoading(false);
|
||||
setImageError(null);
|
||||
@@ -167,7 +167,7 @@ export const SceneCard: React.FC<SceneCardProps> = ({
|
||||
try {
|
||||
setImageLoading(true);
|
||||
setImageError(null);
|
||||
console.log('[SceneCard] Loading image blob for:', currentImageUrl);
|
||||
if (process.env.NODE_ENV === 'development') console.log('[SceneCard] Loading image blob for:', currentImageUrl.split('?')[0]);
|
||||
|
||||
// Check cache again in case it was loaded while we were waiting
|
||||
const cachedUrl = getCachedMedia(currentImageUrl, scene.id);
|
||||
@@ -219,7 +219,7 @@ export const SceneCard: React.FC<SceneCardProps> = ({
|
||||
}
|
||||
return newBlobUrl;
|
||||
});
|
||||
console.log('[SceneCard] Image blob loaded and cached successfully:', currentImageUrl);
|
||||
if (process.env.NODE_ENV === 'development') console.log('[SceneCard] Image blob loaded and cached successfully:', currentImageUrl.split('?')[0]);
|
||||
} catch (err) {
|
||||
console.error('[SceneCard] Failed to load image blob:', err);
|
||||
if (isMounted && imageUrl === currentImageUrl) {
|
||||
@@ -287,7 +287,7 @@ export const SceneCard: React.FC<SceneCardProps> = ({
|
||||
// Check cache first with scene context
|
||||
const cachedUrl = getCachedMedia(job.videoUrl, scene.id);
|
||||
if (cachedUrl) {
|
||||
console.log('[SceneCard] Using cached video:', job.videoUrl, `(scene: ${scene.id})`);
|
||||
if (process.env.NODE_ENV === 'development') console.log('[SceneCard] Using cached video:', job.videoUrl?.split('?')[0], `(scene: ${scene.id})`);
|
||||
setVideoBlobUrl(cachedUrl);
|
||||
setVideoLoading(false);
|
||||
setVideoError(null);
|
||||
@@ -312,7 +312,7 @@ export const SceneCard: React.FC<SceneCardProps> = ({
|
||||
return;
|
||||
}
|
||||
|
||||
console.log('[SceneCard] Loading video blob for:', job.videoUrl);
|
||||
if (process.env.NODE_ENV === 'development') console.log('[SceneCard] Loading video blob for:', (job.videoUrl || '').split('?')[0]);
|
||||
const blobUrl = await fetchMediaBlobUrl(job.videoUrl!);
|
||||
|
||||
if (blobUrl) {
|
||||
@@ -332,7 +332,7 @@ export const SceneCard: React.FC<SceneCardProps> = ({
|
||||
|
||||
testVideo.onloadedmetadata = () => {
|
||||
clearTimeout(timeout);
|
||||
console.log('[SceneCard] Video blob validation successful:', {
|
||||
if (process.env.NODE_ENV === 'development') console.log('[SceneCard] Video blob validation successful:', {
|
||||
duration: testVideo.duration,
|
||||
videoWidth: testVideo.videoWidth,
|
||||
videoHeight: testVideo.videoHeight,
|
||||
@@ -353,7 +353,7 @@ export const SceneCard: React.FC<SceneCardProps> = ({
|
||||
// Cache the validated blob URL with scene context
|
||||
setCachedMedia(job.videoUrl!, blobUrl, 'video', undefined, scene.id);
|
||||
|
||||
console.log('[SceneCard] Video blob loaded, validated, and cached successfully:', job.videoUrl);
|
||||
if (process.env.NODE_ENV === 'development') console.log('[SceneCard] Video blob loaded, validated, and cached successfully:', (job.videoUrl || '').split('?')[0]);
|
||||
} else {
|
||||
// Direct URL fallback
|
||||
setVideoBlobUrl(blobUrl);
|
||||
|
||||
@@ -132,7 +132,7 @@ export const useRenderQueue = ({
|
||||
|
||||
// Skip if job already has imageUrl from script phase - don't override with old video
|
||||
if (job?.imageUrl) {
|
||||
console.log("[useRenderQueue] Skipping old video - job has imageUrl from script phase:", scene.id, "imageUrl:", job.imageUrl);
|
||||
if (process.env.NODE_ENV === 'development') console.log("[useRenderQueue] Skipping old video - job has imageUrl from script phase:", scene.id, "imageUrl:", (job.imageUrl || '').split('?')[0]);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -143,7 +143,7 @@ export const useRenderQueue = ({
|
||||
// If job has finalUrl (audio) or imageUrl from script phase, don't attach old video
|
||||
const isJobEmpty = !job || (!job.imageUrl && !job.videoUrl && !job.finalUrl);
|
||||
if (!isJobEmpty) {
|
||||
console.log("[useRenderQueue] Skipping old video - job has content already:", scene.id, "job:", job);
|
||||
if (process.env.NODE_ENV === 'development') console.log("[useRenderQueue] Skipping old video - job has content already:", scene.id);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -581,15 +581,10 @@ export const useRenderQueue = ({
|
||||
});
|
||||
|
||||
try {
|
||||
console.log("[useRenderQueue] Starting video generation", {
|
||||
if (process.env.NODE_ENV === 'development') console.log("[useRenderQueue] Starting video generation", {
|
||||
sceneId,
|
||||
sceneTitle: scene.title,
|
||||
audioUrl,
|
||||
avatarImageUrl: sceneImageUrl,
|
||||
resolution: targetResolution,
|
||||
prompt: settings?.prompt,
|
||||
seed: settings?.seed,
|
||||
maskImageUrl: settings?.maskImageUrl,
|
||||
});
|
||||
|
||||
const result = await podcastApi.generateVideo({
|
||||
@@ -708,7 +703,7 @@ export const useRenderQueue = ({
|
||||
sceneVideoUrls.push(videoUrl);
|
||||
}
|
||||
|
||||
console.log("[combineFinalVideo] Starting combination with", sceneVideoUrls.length, "videos");
|
||||
if (process.env.NODE_ENV === 'development') console.log("[combineFinalVideo] Starting combination with", sceneVideoUrls.length, "videos");
|
||||
|
||||
// Start combination task
|
||||
const result = await podcastApi.combineVideos({
|
||||
|
||||
@@ -141,11 +141,11 @@ export const SubscriptionProvider: React.FC<SubscriptionProviderProps> = ({ chil
|
||||
// Continue anyway - apiClient interceptor will handle missing token gracefully
|
||||
}
|
||||
|
||||
console.log('SubscriptionContext: Checking subscription for user:', userId);
|
||||
if (process.env.NODE_ENV === 'development') console.log('SubscriptionContext: Checking subscription for user:', userId);
|
||||
const response = await apiClient.get(`/api/subscription/status/${userId}`);
|
||||
const subscriptionData = response.data.data;
|
||||
|
||||
console.log('SubscriptionContext: Received subscription data from backend:', subscriptionData);
|
||||
if (process.env.NODE_ENV === 'development') console.log('SubscriptionContext: Subscription data received:', { active: subscriptionData?.active, plan: subscriptionData?.plan });
|
||||
setSubscription(subscriptionData);
|
||||
// Update ref immediately so callbacks can access latest value
|
||||
subscriptionRef.current = subscriptionData;
|
||||
|
||||
20
frontend/src/utils/devLogger.ts
Normal file
20
frontend/src/utils/devLogger.ts
Normal file
@@ -0,0 +1,20 @@
|
||||
const isDev = process.env.NODE_ENV === 'development';
|
||||
|
||||
export const devLog = {
|
||||
log: (...args: any[]) => { if (isDev) console.log(...args); },
|
||||
warn: (...args: any[]) => { if (isDev) console.warn(...args); },
|
||||
error: (...args: any[]) => { console.error(...args); },
|
||||
info: (...args: any[]) => { if (isDev) console.info(...args); },
|
||||
};
|
||||
|
||||
export const sanitizeUrl = (url: string): string => {
|
||||
try {
|
||||
const parsed = new URL(url, window.location.origin);
|
||||
if (parsed.searchParams.has('token')) {
|
||||
parsed.searchParams.set('token', '***');
|
||||
}
|
||||
return parsed.pathname + (parsed.search ? parsed.search : '');
|
||||
} catch {
|
||||
return url.split('?')[0];
|
||||
}
|
||||
};
|
||||
@@ -102,9 +102,11 @@ class MediaCache {
|
||||
this.evictOldest();
|
||||
}
|
||||
|
||||
console.log(`[MediaCache] Cached ${mediaType}:`, url,
|
||||
sceneId ? `(scene: ${sceneId})` : '',
|
||||
projectId ? `(project: ${projectId})` : '');
|
||||
if (process.env.NODE_ENV === 'development') {
|
||||
console.log(`[MediaCache] Cached ${mediaType}:`, url.split('?')[0],
|
||||
sceneId ? `(scene: ${sceneId})` : '',
|
||||
projectId ? `(project: ${projectId})` : '');
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
Reference in New Issue
Block a user