userIdc2024 commited on
Commit
f20c3e2
·
verified ·
1 Parent(s): 08e972f

Update app_pages/video_hashid_generation.py

Browse files
Files changed (1) hide show
  1. app_pages/video_hashid_generation.py +187 -113
app_pages/video_hashid_generation.py CHANGED
@@ -1,8 +1,9 @@
1
  import os
 
2
  import zipfile
3
  import tempfile
4
  import streamlit as st
5
- from generator_function.video_hashid_function import process_video_with_hash_info
6
 
7
  VIDEO_EXTS = (".mp4", ".avi", ".mov", ".mkv", ".wmv", ".flv", ".webm")
8
 
@@ -14,140 +15,213 @@ def _is_valid_zip_member(name: str) -> bool:
14
  return False
15
  return True
16
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
17
  def render_video_hashid(uid: str):
18
  st.markdown("#### Change video hashid")
19
 
20
- uploaded_file = st.file_uploader("Upload a video (.mp4) or a ZIP file of videos", type=["zip", "mp4"])
 
 
21
 
22
- num_variations = st.slider("Number of variations per video", min_value=1, max_value=10, value=1, step=1)
 
 
23
 
24
  st.markdown("**Border Options**")
25
- enable_border = st.checkbox("Add border to videos", value=False)
26
  border_width = 0
27
  border_color = "#000000"
28
  if enable_border:
29
  col1, col2 = st.columns(2)
30
  with col1:
31
- border_width = st.slider("Border width (px)", min_value=1, max_value=50, value=10, step=1)
 
 
32
  with col2:
33
- border_color = st.color_picker("Border color", value="#000000")
34
 
35
  generate_clicked = st.button(
36
  "Generate Augmented Videos",
37
  type="primary",
38
  width='stretch',
39
- disabled=uploaded_file is None
 
40
  )
41
 
42
- if not (generate_clicked and uploaded_file):
43
- return
44
-
45
- is_zip = uploaded_file.name.lower().endswith(".zip")
46
 
47
- with tempfile.TemporaryDirectory() as extract_dir, tempfile.TemporaryDirectory() as output_dir:
48
- results = []
49
- skipped = []
50
- video_files = []
51
 
52
- if is_zip:
53
- zip_path = os.path.join(extract_dir, uploaded_file.name)
54
- with open(zip_path, "wb") as f:
55
- f.write(uploaded_file.getvalue())
56
 
57
- with zipfile.ZipFile(zip_path, "r") as z:
58
- members = [m for m in z.namelist() if _is_valid_zip_member(m)]
59
- z.extractall(extract_dir, members)
60
 
61
- # Pre-collect valid video files so we know the total
62
- for root, _, files in os.walk(extract_dir):
63
- if "__MACOSX" in root.split(os.sep):
64
- continue
65
- for file in sorted(files):
66
- if file.startswith("._") or file.startswith("."):
67
- continue
68
- if not file.lower().endswith(VIDEO_EXTS):
69
- continue
70
- input_path = os.path.join(root, file)
71
- try:
72
- if os.path.getsize(input_path) < 1024 * 20:
73
- skipped.append(f"{input_path} (too small)")
74
- continue
75
- except OSError:
76
- skipped.append(f"{input_path} (stat failed)")
77
- continue
78
- video_files.append(input_path)
79
- else:
80
- video_path = os.path.join(extract_dir, uploaded_file.name)
81
- with open(video_path, "wb") as f:
82
- f.write(uploaded_file.getvalue())
83
- if os.path.getsize(video_path) < 1024 * 20:
84
- skipped.append(f"{uploaded_file.name} (too small)")
85
- else:
86
- video_files.append(video_path)
87
-
88
- total_tasks = len(video_files) * num_variations
89
- progress_bar = st.progress(0, text="Starting...")
90
- completed = 0
91
-
92
- for video_num, input_path in enumerate(video_files, 1):
93
- for i in range(num_variations):
94
- label = (
95
- f"Video {video_num} of {len(video_files)}"
96
- + (f" — variation {i + 1}/{num_variations}" if num_variations > 1 else "")
97
- + f": {os.path.basename(input_path)}"
98
- )
99
- progress_bar.progress(completed / total_tasks if total_tasks else 1.0, text=label)
100
- try:
101
- r = process_video_with_hash_info(
102
- input_path=input_path,
103
- output_path=output_dir,
104
- variation_idx=i + 1,
105
- border_width=border_width,
106
- border_color=border_color,
107
- )
108
- if r:
109
- results.append(r)
110
- except Exception as e:
111
- skipped.append(f"{os.path.basename(input_path)} ({e})")
112
- completed += 1
113
-
114
- progress_bar.progress(1.0, text=f"Done — {len(results)} video(s) processed.")
115
-
116
- if not results:
117
- st.error("No valid videos were processed. The file may be too small, corrupted, or (for ZIPs) contain only macOS metadata.")
118
- if skipped:
119
- with st.expander("Skipped / errors"):
120
- st.write("\n".join(skipped))
121
- return
122
-
123
- st.success(f"Processed {len(results)} video(s). Skipped {len(skipped)} file(s).")
124
 
125
- if skipped:
126
- with st.expander("Skipped / errors"):
127
- st.write("\n".join(skipped))
 
 
 
 
128
 
129
- if len(results) == 1:
130
- r = results[0]
131
- with open(r["output_path"], "rb") as f:
132
- st.download_button(
133
- "Download Augmented Video (MP4)",
134
- data=f.read(),
135
- file_name=r["output_name"],
136
- mime="video/mp4",
137
- use_container_width=True
138
- )
139
- else:
140
- final_zip_path = os.path.join(output_dir, "augmented_videos.zip")
141
- import zipfile as zf
142
- with zf.ZipFile(final_zip_path, "w", compression=zf.ZIP_DEFLATED) as outzip:
143
- for r in results:
144
- outzip.write(r["output_path"], arcname=r["output_name"])
145
-
146
- with open(final_zip_path, "rb") as f:
147
- st.download_button(
148
- "Download All Augmented Videos (ZIP)",
149
- data=f.read(),
150
- file_name="augmented_videos.zip",
151
- mime="application/zip",
152
- use_container_width=True
153
- )
 
1
  import os
2
+ import random
3
  import zipfile
4
  import tempfile
5
  import streamlit as st
6
+ from generator_function.video_hashid_function import process_video_with_hash_info, SAFE_EFFECTS
7
 
8
  VIDEO_EXTS = (".mp4", ".avi", ".mov", ".mkv", ".wmv", ".flv", ".webm")
9
 
 
15
  return False
16
  return True
17
 
18
+ def _pick_effects(pool: list, count: int) -> list:
19
+ """Return `count` effect names drawn from `pool`, distinct within each shuffled pass."""
20
+ effects = []
21
+ remaining = []
22
+ while len(effects) < count:
23
+ if not remaining:
24
+ remaining = list(pool)
25
+ random.shuffle(remaining)
26
+ effects.append(remaining.pop())
27
+ return effects
28
+
29
+ def _collect_video_files(uploaded_file, extract_dir):
30
+ skipped = []
31
+ video_files = []
32
+ is_zip = uploaded_file.name.lower().endswith(".zip")
33
+
34
+ if is_zip:
35
+ zip_path = os.path.join(extract_dir, uploaded_file.name)
36
+ with open(zip_path, "wb") as f:
37
+ f.write(uploaded_file.getvalue())
38
+
39
+ with zipfile.ZipFile(zip_path, "r") as z:
40
+ members = [m for m in z.namelist() if _is_valid_zip_member(m)]
41
+ z.extractall(extract_dir, members)
42
+
43
+ for root, _, files in os.walk(extract_dir):
44
+ if "__MACOSX" in root.split(os.sep):
45
+ continue
46
+ for file in sorted(files):
47
+ if file.startswith("._") or file.startswith("."):
48
+ continue
49
+ if not file.lower().endswith(VIDEO_EXTS):
50
+ continue
51
+ input_path = os.path.join(root, file)
52
+ try:
53
+ if os.path.getsize(input_path) < 1024 * 20:
54
+ skipped.append(f"{input_path} (too small)")
55
+ continue
56
+ except OSError:
57
+ skipped.append(f"{input_path} (stat failed)")
58
+ continue
59
+ video_files.append(input_path)
60
+ else:
61
+ video_path = os.path.join(extract_dir, uploaded_file.name)
62
+ with open(video_path, "wb") as f:
63
+ f.write(uploaded_file.getvalue())
64
+ if os.path.getsize(video_path) < 1024 * 20:
65
+ skipped.append(f"{uploaded_file.name} (too small)")
66
+ else:
67
+ video_files.append(video_path)
68
+
69
+ return video_files, skipped
70
+
71
+ def _generate_and_render(video_files, skipped, output_dir, num_variations, border_width, border_color, effects_pool=None):
72
+ if effects_pool:
73
+ num_variations = len(effects_pool)
74
+ results = []
75
+ total_tasks = len(video_files) * num_variations
76
+ progress_bar = st.progress(0, text="Starting...")
77
+ completed = 0
78
+
79
+ for video_num, input_path in enumerate(video_files, 1):
80
+ effects_for_video = _pick_effects(effects_pool, num_variations) if effects_pool else [None] * num_variations
81
+ for i in range(num_variations):
82
+ effect_name = effects_for_video[i]
83
+ label = (
84
+ f"Video {video_num} of {len(video_files)}"
85
+ + (f" — variation {i + 1}/{num_variations}" if num_variations > 1 else "")
86
+ + (f" [{effect_name}]" if effect_name else "")
87
+ + f": {os.path.basename(input_path)}"
88
+ )
89
+ progress_bar.progress(completed / total_tasks if total_tasks else 1.0, text=label)
90
+ try:
91
+ r = process_video_with_hash_info(
92
+ input_path=input_path,
93
+ output_path=output_dir,
94
+ variation_idx=i + 1,
95
+ border_width=border_width,
96
+ border_color=border_color,
97
+ effect_name=effect_name,
98
+ )
99
+ if r:
100
+ results.append(r)
101
+ except Exception as e:
102
+ skipped.append(f"{os.path.basename(input_path)} ({e})")
103
+ completed += 1
104
+
105
+ progress_bar.progress(1.0, text=f"Done — {len(results)} video(s) processed.")
106
+
107
+ if not results:
108
+ st.error("No valid videos were processed. The file may be too small, corrupted, or (for ZIPs) contain only macOS metadata.")
109
+ if skipped:
110
+ with st.expander("Skipped / errors"):
111
+ st.write("\n".join(skipped))
112
+ return
113
+
114
+ st.success(f"Processed {len(results)} video(s). Skipped {len(skipped)} file(s).")
115
+
116
+ if skipped:
117
+ with st.expander("Skipped / errors"):
118
+ st.write("\n".join(skipped))
119
+
120
+
121
+ if len(results) == 1:
122
+ r = results[0]
123
+ with open(r["output_path"], "rb") as f:
124
+ st.download_button(
125
+ "Download Augmented Video (MP4)",
126
+ data=f.read(),
127
+ file_name=r["output_name"],
128
+ mime="video/mp4",
129
+ use_container_width=True
130
+ )
131
+ else:
132
+ final_zip_path = os.path.join(output_dir, "augmented_videos.zip")
133
+ with zipfile.ZipFile(final_zip_path, "w", compression=zipfile.ZIP_DEFLATED) as outzip:
134
+ for r in results:
135
+ outzip.write(r["output_path"], arcname=r["output_name"])
136
+
137
+ with open(final_zip_path, "rb") as f:
138
+ st.download_button(
139
+ "Download All Augmented Videos (ZIP)",
140
+ data=f.read(),
141
+ file_name="augmented_videos.zip",
142
+ mime="application/zip",
143
+ use_container_width=True
144
+ )
145
+
146
  def render_video_hashid(uid: str):
147
  st.markdown("#### Change video hashid")
148
 
149
+ uploaded_file = st.file_uploader(
150
+ "Upload a video (.mp4) or a ZIP file of videos", type=["zip", "mp4"], key="hashid_uploader"
151
+ )
152
 
153
+ num_variations = st.slider(
154
+ "Number of variations per video", min_value=1, max_value=10, value=1, step=1, key="hashid_variations"
155
+ )
156
 
157
  st.markdown("**Border Options**")
158
+ enable_border = st.checkbox("Add border to videos", value=False, key="hashid_enable_border")
159
  border_width = 0
160
  border_color = "#000000"
161
  if enable_border:
162
  col1, col2 = st.columns(2)
163
  with col1:
164
+ border_width = st.slider(
165
+ "Border width (px)", min_value=1, max_value=50, value=10, step=1, key="hashid_border_width"
166
+ )
167
  with col2:
168
+ border_color = st.color_picker("Border color", value="#000000", key="hashid_border_color")
169
 
170
  generate_clicked = st.button(
171
  "Generate Augmented Videos",
172
  type="primary",
173
  width='stretch',
174
+ disabled=uploaded_file is None,
175
+ key="hashid_generate"
176
  )
177
 
178
+ if generate_clicked and uploaded_file:
179
+ with tempfile.TemporaryDirectory() as extract_dir, tempfile.TemporaryDirectory() as output_dir:
180
+ video_files, skipped = _collect_video_files(uploaded_file, extract_dir)
181
+ _generate_and_render(video_files, skipped, output_dir, num_variations, border_width, border_color)
182
 
183
+ st.divider()
 
 
 
184
 
185
+ # ---------------- Apply Video Filters ----------------
186
+ st.markdown("#### Apply video filters")
 
 
187
 
188
+ filters_uploaded_file = st.file_uploader(
189
+ "Upload a video (.mp4) or a ZIP file of videos", type=["zip", "mp4"], key="filters_uploader"
190
+ )
191
 
192
+ st.markdown("**Border Options**")
193
+ filters_enable_border = st.checkbox("Add border to videos", value=False, key="filters_enable_border")
194
+ filters_border_width = 0
195
+ filters_border_color = "#000000"
196
+ if filters_enable_border:
197
+ col1, col2 = st.columns(2)
198
+ with col1:
199
+ filters_border_width = st.slider(
200
+ "Border width (px)", min_value=1, max_value=50, value=10, step=1, key="filters_border_width"
201
+ )
202
+ with col2:
203
+ filters_border_color = st.color_picker("Border color", value="#000000", key="filters_border_color")
204
+
205
+ st.markdown("**Filters**")
206
+ selected_filters = st.multiselect(
207
+ "Select filters to apply — one output video is generated per selected filter, per input video",
208
+ options=list(SAFE_EFFECTS.keys()),
209
+ default=list(SAFE_EFFECTS.keys()),
210
+ key="filters_pool"
211
+ )
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
212
 
213
+ filters_generate_clicked = st.button(
214
+ "Generate Filtered Videos",
215
+ type="primary",
216
+ width='stretch',
217
+ disabled=filters_uploaded_file is None or not selected_filters,
218
+ key="filters_generate"
219
+ )
220
 
221
+ if filters_generate_clicked and filters_uploaded_file:
222
+ with tempfile.TemporaryDirectory() as extract_dir, tempfile.TemporaryDirectory() as output_dir:
223
+ video_files, skipped = _collect_video_files(filters_uploaded_file, extract_dir)
224
+ _generate_and_render(
225
+ video_files, skipped, output_dir, len(selected_filters),
226
+ filters_border_width, filters_border_color, effects_pool=selected_filters
227
+ )