feat(social): 업로드 폼에 저장된 영상 SEO 메타데이터를 표시
값이 있으면 DB 결과를 바로 채우고, 없으면 video_id 기준으로 한 번만 생성한다.
This commit is contained in:
parent
63d60caabd
commit
bdb581459d
@ -142,10 +142,7 @@ const SocialPostingModal: React.FC<SocialPostingModalProps> = ({
|
||||
const channelDropdownRef = useRef<HTMLDivElement>(null);
|
||||
const privacyDropdownRef = useRef<HTMLDivElement>(null);
|
||||
const hasBeenOpenedRef = useRef(false);
|
||||
const loadedForTaskIdRef = useRef<string | null>(null);
|
||||
const loadedAtRef = useRef<number>(0);
|
||||
const seoCache = useRef<Map<string, { title: string; description: string; tags: string }>>(new Map());
|
||||
const SEO_CACHE_TTL = 50 * 60 * 1000;
|
||||
const loadedForVideoIdRef = useRef<number | null>(null);
|
||||
|
||||
// Upload progress modal state
|
||||
const [showUploadProgress, setShowUploadProgress] = useState(false);
|
||||
@ -212,28 +209,30 @@ const SocialPostingModal: React.FC<SocialPostingModalProps> = ({
|
||||
|
||||
// 소셜 계정 로드
|
||||
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;
|
||||
const videoId = video?.video_id ?? null;
|
||||
if (!videoId || videoId === loadedForVideoIdRef.current) {
|
||||
return;
|
||||
}
|
||||
|
||||
loadedForVideoIdRef.current = videoId;
|
||||
|
||||
if (video?.title) {
|
||||
setTitle(video.title);
|
||||
setDescription(video.description || '');
|
||||
setTags((video.hashtags || []).join(','));
|
||||
setIsLoadingAutoDescription(false);
|
||||
return;
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
}, [isOpen, video?.task_id]);
|
||||
}, [isOpen, video?.video_id, video?.title, video?.description, video?.hashtags]);
|
||||
|
||||
const loadSocialAccounts = async () => {
|
||||
setIsLoadingAccounts(true);
|
||||
@ -259,29 +258,20 @@ const SocialPostingModal: React.FC<SocialPostingModalProps> = ({
|
||||
};
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
@ -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 자동완성 응답
|
||||
|
||||
Loading…
Reference in New Issue
Block a user