diff --git "a/app.py" "b/app.py" --- "a/app.py" +++ "b/app.py" @@ -1,7 +1,7 @@ """ Simple Video Editor - 허깅페이스 스페이스용 CapCut/VEED 스타일 간단 영상 편집기 (흰색 테마) -Gradio 네이티브 파일 업로드 - JavaScript 실행 문제 해결 +iframe + base64 방식으로 JavaScript 실행 보장 """ import gradio as gr @@ -11,1838 +11,554 @@ import json def get_editor_html(media_data="[]"): """에디터 HTML 생성 - 미디어 데이터 포함""" - return f""" - + return f""" Simple Video Editor -
-
- -
-
- - - - - - - Simple Video Editor -
-
- - +
+
+
+ + Simple Video Editor +
+
+ + +
+
+
+
+
📁 미디어
+
+
⬆️ 위의 파일 업로드를
사용하세요
+
- - -
- -
-
📁 미디어
-
-
- ⬆️ 위의 파일 업로드를
사용하세요 -
-
+
+
+
+ +

타임라인에 미디어를 추가하세요

- - -
-
-
- - - - -

타임라인에 미디어를 추가하세요

-
-
- -
- - - - - -
- 00:00.00 / 00:00.00 -
- -
+
+ + + + + +
00:00.00 / 00:00.00
+
- - -
-
⚙️ 속성
-
-
- 클립을 선택하면
속성을 편집할 수 있습니다 -
-
+
+
+
⚙️ 속성
+
클립을 선택하면
속성을 편집할 수 있습니다
+
+
+
+
+ + + +
+ + +
- - -
-
- - - -
- - - - - - - - - - - - +
+
+
+
+
영상
+
-
-
-
-
-
-
- - - - - 영상 -
-
-
-
-
- - - - - - 오디오 -
-
-
+
+
오디오
+
-
+
- -
준비됨 | 미디어: 0개 | 클립: 0개
- - - - - - + + - - -""" +""" def process_file(file): - """업로드된 파일을 처리하여 미디어 데이터 생성""" if file is None: return [] - results = [] - - # file이 리스트인 경우 처리 files = file if isinstance(file, list) else [file] - for f in files: if f is None: continue - - # 파일 경로 가져오기 file_path = f.name if hasattr(f, 'name') else f file_name = os.path.basename(file_path) - - # 파일 타입 결정 ext = file_name.lower().split('.')[-1] if ext in ['mp4', 'webm', 'mov', 'avi', 'mkv']: file_type = 'video' @@ -1855,67 +571,30 @@ def process_file(file): mime = f'audio/{ext}' else: continue - - # Base64로 인코딩 with open(file_path, 'rb') as fp: data = base64.b64encode(fp.read()).decode('utf-8') - - data_url = f'data:{mime};base64,{data}' - - results.append({ - 'name': file_name, - 'type': file_type, - 'dataUrl': data_url - }) - + results.append({'name': file_name, 'type': file_type, 'dataUrl': f'data:{mime};base64,{data}'}) return results -def create_interface(): - """Gradio 인터페이스 생성""" - - with gr.Blocks(title="Simple Video Editor") as demo: - - gr.Markdown("## 🎬 Simple Video Editor - 파일을 업로드하면 자동으로 타임라인에 추가됩니다") - - with gr.Row(): - file_input = gr.File( - label="📁 파일 업로드 (영상/이미지/오디오) - 여러 파일 선택 가능", - file_count="multiple", - file_types=["video", "image", "audio"], - height=80, - elem_classes=["file-upload"] - ) - - # 에디터 HTML - 초기 상태 - editor = gr.HTML(get_editor_html("[]"), elem_id="editor-frame") - - def on_file_upload(files): - """파일 업로드 시 에디터 HTML을 미디어 데이터와 함께 재생성""" - if not files: - return get_editor_html("[]") - - results = process_file(files) - if not results: - return get_editor_html("[]") - - # JSON으로 변환하여 HTML에 포함 - media_json = json.dumps(results, ensure_ascii=False) - return get_editor_html(media_json) - - file_input.change( - fn=on_file_upload, - inputs=[file_input], - outputs=[editor] - ) - - return demo +def create_editor_iframe(media_data): + media_json = json.dumps(media_data, ensure_ascii=False) + html_content = get_editor_html(media_json) + html_b64 = base64.b64encode(html_content.encode('utf-8')).decode('utf-8') + return f'' + +with gr.Blocks(title="Simple Video Editor") as demo: + gr.Markdown("## 🎬 Simple Video Editor") + gr.Markdown("파일을 업로드하면 자동으로 타임라인에 추가됩니다. 미디어를 더블클릭해도 추가할 수 있습니다.") + file_input = gr.File(label="📁 파일 업로드 (영상/이미지/오디오) - 여러 파일 선택 가능", file_count="multiple", file_types=["video", "image", "audio"]) + editor_html = gr.HTML(value=create_editor_iframe([])) + def on_file_upload(files): + if not files: + return create_editor_iframe([]) + media_data = process_file(files) + return create_editor_iframe(media_data) + file_input.change(fn=on_file_upload, inputs=[file_input], outputs=[editor_html]) if __name__ == "__main__": - demo = create_interface() - demo.launch( - server_name="0.0.0.0", - server_port=7860, - share=False - ) \ No newline at end of file + demo.launch(server_name="0.0.0.0", server_port=7860) \ No newline at end of file