Prechádzať zdrojové kódy

add checking zip in web server.

tomoya 1 rok pred
rodič
commit
47d484545f

+ 0 - 1
backend/app/app/aianchor/__init__.py

@@ -1 +0,0 @@
-from .videomaker import *

+ 70 - 0
backend/app/app/aianchor/utils2.py

@@ -0,0 +1,70 @@
+import pandas as pd
+from pathlib import Path
+import zipfile
+from io import BytesIO
+from chardet.universaldetector import UniversalDetector
+
+DEFAULT_ENCODING = "utf-8"
+
+class VideoMakerError(Exception):
+  pass
+
+def guess_codec(filenames: list) -> str:
+  codec_detector = UniversalDetector()
+  for filename in filenames:
+    codec_detector.feed(filename.encode('cp437'))
+    if codec_detector.done:
+      break
+
+  result = codec_detector.close()
+  encoding = result.get("encoding")
+  return encoding or DEFAULT_ENCODING
+
+def check_zip(zip_filepath:str):
+  path = Path(zip_filepath)
+  with zipfile.ZipFile(str(path)) as zf:
+    filenames = [x for x in zf.namelist() if not x.endswith('/')]
+    result = guess_codec(filenames)
+    true_filenames = [x.encode('cp437').decode(result) for x in zf.namelist() if not x.endswith('/')]
+    print(true_filenames)
+    scenarios_files = [(x, i) for i, x in enumerate(true_filenames) if Path(x).suffix in [".xlsx", ".csv"] and not Path(x).name.startswith("._") and Path(x).stem != "style"]
+    print(scenarios_files)
+    
+    if len(scenarios_files) == 0:
+      raise VideoMakerError("no excel or csv file in zip.")
+    if len(scenarios_files) > 1:
+      raise VideoMakerError("too many excel or csv file in zip.")
+    f = zf.read(filenames[scenarios_files[0][1]])
+    if Path(scenarios_files[0][0]).suffix == ".xlsx":
+      table = pd.read_excel(BytesIO(f), dtype=object)
+    elif Path(scenarios_files[0][0]).suffix == ".csv":
+      table = pd.read_csv(BytesIO(f), dtype=object)
+    table.reset_index(inplace=True)
+    print(table)
+    
+    stems = [Path(x).stem for x in true_filenames]
+    for i in range(len(table)):
+      # excel 裡的圖檔跟zip裡的檔案要一致
+      if not table.loc[i, ['素材']].isna().item():
+        img =  table.loc[i, ['素材']].item()
+        print(img)
+
+        img_files = [x.strip() for x in img.split(',')]
+        for img in img_files:
+          print(img)
+          n = stems.count(img)
+          if n == 0:
+            raise VideoMakerError(f"{img}: no such media file in zip.")
+          elif n > 1:
+            raise VideoMakerError(f'too many same name media files as {img} in zip')
+      
+      # 需要tts文字或音檔
+      if not table.loc[i, ['字幕']].isna().item():
+        if not '音檔' in table.columns or table.loc[i, ['音檔']].isna().item():
+          raise VideoMakerError(f'text or voice file is needed at scene {i+1}.')
+        voice_file = table.loc[i, ['音檔']].item()
+        n = stems.count(voice_file)
+        if n != 1:
+          raise VideoMakerError(f"voice file is can't find is zip at scene {i+1}.")
+  
+  return True

+ 15 - 8
frontend/src/views/main/Upload.vue

@@ -7,13 +7,7 @@ import { wsUrl } from "@/env";
 import type { VideoCreate } from "@/interfaces";
 import router from "@/router";
 import Dialog from "@/components/Dialog.vue";
-
-// props
-let dialog = reactive({
-  msg: "影片處理需要約 5-10 分鐘,敬請耐心等候",
-  state: "info",
-  show: false,
-});
+import type { VideoUploaded } from "@/interfaces";
 
 const { t } = useI18n();
 const mainStore = useMainStore();
@@ -25,6 +19,13 @@ const Form = ref();
 let anchor = ref(0);
 let templateId = ref(0);
 
+// props
+let dialog = reactive({
+  msg: "",
+  state: "info",
+  show: false,
+});
+
 const anchorList = reactive([
   {
     anchor_id: 0,
@@ -190,7 +191,13 @@ async function Submit() {
       lang_id: 0,
     };
 
-    await mainStore.uploadPlot(video_data, zipFiles.value[0]);
+    const ret:VideoUploaded = await mainStore.uploadPlot(video_data, zipFiles.value[0]);
+    if (ret.accepted) {
+      dialog.msg = t("acceptZipMessage")
+    }
+    else {
+      dialog.msg = ret.error_message!
+    }
     valid.value = true;
     // (Form as any).value.reset();
   }