diff --git a/src/components/SocialPostingModal.tsx b/src/components/SocialPostingModal.tsx index 501c977..50e8cd8 100644 --- a/src/components/SocialPostingModal.tsx +++ b/src/components/SocialPostingModal.tsx @@ -142,10 +142,7 @@ const SocialPostingModal: React.FC = ({ const channelDropdownRef = useRef(null); const privacyDropdownRef = useRef(null); const hasBeenOpenedRef = useRef(false); - const loadedForTaskIdRef = useRef(null); - const loadedAtRef = useRef(0); - const seoCache = useRef>(new Map()); - const SEO_CACHE_TTL = 50 * 60 * 1000; + const loadedForVideoIdRef = useRef(null); // Upload progress modal state const [showUploadProgress, setShowUploadProgress] = useState(false); @@ -212,28 +209,30 @@ const SocialPostingModal: React.FC = ({ // 소셜 계정 로드 useEffect(() => { - if (!isOpen) return; - - const now = Date.now(); + if (!isOpen) { + loadedForVideoIdRef.current = null; + return; + } loadSocialAccounts(); - const taskId = video?.task_id ?? null; - const expired = now - loadedAtRef.current > SEO_CACHE_TTL; - - if (taskId && (taskId !== loadedForTaskIdRef.current || expired)) { - loadedForTaskIdRef.current = taskId; - loadedAtRef.current = now; - loadAutocomplete(); - } else if (taskId) { - const cached = seoCache.current.get(taskId); - if (cached) { - setTitle(cached.title); - setDescription(cached.description); - setTags(cached.tags); - } + const videoId = video?.video_id ?? null; + if (!videoId || videoId === loadedForVideoIdRef.current) { + return; } - }, [isOpen, video?.task_id]); + + loadedForVideoIdRef.current = videoId; + + if (video?.title) { + setTitle(video.title); + setDescription(video.description || ''); + setTags((video.hashtags || []).join(',')); + setIsLoadingAutoDescription(false); + return; + } + + loadAutocomplete(); + }, [isOpen, video?.video_id, video?.title, video?.description, video?.hashtags]); const loadSocialAccounts = async () => { setIsLoadingAccounts(true); @@ -259,29 +258,20 @@ const SocialPostingModal: React.FC = ({ }; const loadAutocomplete = async () => { - if (!video?.task_id) return; + if (!video?.video_id) return; setIsLoadingAutoDescription(true); try { const requestPayload = { - task_id : video.task_id, + video_id: video.video_id, }; - // Call autoSEO API - console.log('[Upload] Request payload:', requestPayload); const autoSeoResponse = await getAutoSeoYoutube(requestPayload); - // 각 필드가 있을 때만 덮어씌움 (기존 값 보호) if (autoSeoResponse.title) setTitle(autoSeoResponse.title); if (autoSeoResponse.description) setDescription(autoSeoResponse.description); if (autoSeoResponse.keywords) setTags(autoSeoResponse.keywords.join(',')); - seoCache.current.set(video.task_id, { - title: autoSeoResponse.title || '', - description: autoSeoResponse.description || '', - tags: autoSeoResponse.keywords?.join(',') || '', - }); } catch (error) { console.error('Failed to load autocomplete:', error); - // 실패해도 사용자에게 별도 알림 없이 조용히 처리 } finally { setIsLoadingAutoDescription(false); } diff --git a/src/types/api.ts b/src/types/api.ts index e75525c..854442e 100644 --- a/src/types/api.ts +++ b/src/types/api.ts @@ -278,6 +278,9 @@ export interface VideoListItem { result_movie_url: string; poster_url?: string | null; thumbnail_url?: string; + title?: string | null; + description?: string | null; + hashtags?: string[] | null; created_at: string; like_count: number; comment_count: number; @@ -394,7 +397,7 @@ export interface SocialDisconnectResponse { // 유튜브 SEO Description 자동완성 요청 export interface YTAutoSeoRequest { - task_id: string; // 아카이브의 비디오 ID + video_id: number; } // 유튜브 SEO Description 자동완성 응답