nazib61 commited on
Commit
41e1b2b
Β·
verified Β·
1 Parent(s): 4887e95

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +58 -53
app.py CHANGED
@@ -2,96 +2,101 @@ import gradio as gr
2
  import subprocess
3
  import os
4
  import uuid
 
5
 
6
  def initialize_env():
7
  if not os.path.exists("node_modules"):
8
- print("Installing node_modules...")
9
  subprocess.run(["npm", "install"], check=True)
10
 
11
  initialize_env()
12
 
13
- def process_video(query, start_time, end_time):
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
14
  if not query:
15
  return None, "⚠️ Please enter a keyword."
16
 
17
- # 1. Scrape the URL using Node.js
18
  search_query = query if "video" in query.lower() else f"{query} video"
 
19
  try:
 
 
20
  result = subprocess.run(
21
  ["node", "scraper.js", search_query],
22
  capture_output=True, text=True, timeout=90
23
  )
24
 
25
- stdout = result.stdout.strip()
26
- lines = stdout.split('\n')
27
- video_url = None
28
- for line in lines:
29
- if line.strip().startswith("http"):
30
- video_url = line.strip()
31
- break
32
 
33
- if not video_url:
34
- return None, f"❌ No video found. Logs: {result.stderr[:100]}"
35
 
36
- # 2. Trim the video using FFmpeg
37
- # We create a unique filename for the trimmed video
38
- output_filename = f"trimmed_{uuid.uuid4().hex[:8]}.mp4"
39
-
40
- print(f"Trimming video: {start_time}s to {end_time}s")
41
-
42
- # FFmpeg Command Explanation:
43
- # -ss: Start time
44
- # -to: End time
45
- # -i: Input URL (FFmpeg can stream directly from the URL)
46
- # -c:v libx264: Re-encode to ensure precision for decimals like 3.79
 
 
 
47
 
 
 
 
 
 
48
  ffmpeg_cmd = [
49
- "ffmpeg",
50
- "-ss", str(start_time),
51
- "-to", str(end_time),
52
- "-i", video_url,
53
- "-c:v", "libx264",
54
- "-c:a", "aac",
55
- "-strict", "experimental",
56
- "-y", # Overwrite if exists
57
- output_filename
58
  ]
59
 
60
- # If end_time is 0, we assume the user wants the whole video from the start_time
61
  if end_time <= 0:
62
- ffmpeg_cmd.pop(3) # Remove "-to"
63
- ffmpeg_cmd.pop(3) # Remove the end_time value
64
 
65
  subprocess.run(ffmpeg_cmd, check=True)
 
66
 
67
- return output_filename, f"βœ… Success! Trimmed from {start_time}s to {end_time}s"
68
-
69
- except subprocess.CalledProcessError as e:
70
- return None, f"❌ FFmpeg Error: Maybe the start/end time is longer than the video?"
71
  except Exception as e:
72
- return None, f"❌ System Error: {str(e)}"
73
 
74
  # --- Gradio UI ---
75
  with gr.Blocks(theme=gr.themes.Soft()) as demo:
76
- gr.Markdown("# πŸ“Œ Pinterest Video Search & Trim")
77
 
78
  with gr.Row():
79
  with gr.Column():
80
- query_input = gr.Textbox(label="Search Query", placeholder="e.g. Minecraft Gameplay")
 
 
81
  with gr.Row():
82
- start_input = gr.Number(label="Start Second (e.g. 1.5)", value=0)
83
- end_input = gr.Number(label="End Second (0 = Full video)", value=0)
84
- btn = gr.Button("πŸš€ Search & Trim", variant="primary")
 
85
 
86
  with gr.Column():
87
- video_output = gr.Video(label="Trimmed Result")
88
  status_output = gr.Textbox(label="Status")
89
 
90
- btn.click(
91
- fn=process_video,
92
- inputs=[query_input, start_input, end_input],
93
- outputs=[video_output, status_output]
94
- )
95
 
96
- if __name__ == "__main__":
97
- demo.launch()
 
2
  import subprocess
3
  import os
4
  import uuid
5
+ import json
6
 
7
  def initialize_env():
8
  if not os.path.exists("node_modules"):
 
9
  subprocess.run(["npm", "install"], check=True)
10
 
11
  initialize_env()
12
 
13
+ def get_video_dimensions(url):
14
+ """Uses ffprobe to check if video is Portrait or Landscape"""
15
+ try:
16
+ cmd = [
17
+ "ffprobe", "-v", "error", "-select_streams", "v:0",
18
+ "-show_entries", "stream=width,height", "-of", "json", url
19
+ ]
20
+ result = subprocess.run(cmd, capture_output=True, text=True)
21
+ data = json.loads(result.stdout)
22
+ width = data['streams'][0]['width']
23
+ height = data['streams'][0]['height']
24
+ return width, height
25
+ except:
26
+ return 0, 0
27
+
28
+ def process_video(query, orientation, start_time, end_time):
29
  if not query:
30
  return None, "⚠️ Please enter a keyword."
31
 
 
32
  search_query = query if "video" in query.lower() else f"{query} video"
33
+
34
  try:
35
+ # 1. Get multiple potential URLs from Node
36
+ # I modified the scraper to return multiple links separated by commas
37
  result = subprocess.run(
38
  ["node", "scraper.js", search_query],
39
  capture_output=True, text=True, timeout=90
40
  )
41
 
42
+ all_urls = [line.strip() for line in result.stdout.split('\n') if line.strip().startswith("http")]
 
 
 
 
 
 
43
 
44
+ if not all_urls:
45
+ return None, "❌ No videos found at all."
46
 
47
+ # 2. Filter by Orientation
48
+ selected_url = None
49
+ for url in all_urls:
50
+ if orientation == "Any":
51
+ selected_url = url
52
+ break
53
+
54
+ w, h = get_video_dimensions(url)
55
+ if orientation == "Portrait" and h > w:
56
+ selected_url = url
57
+ break
58
+ if orientation == "Landscape" and w > h:
59
+ selected_url = url
60
+ break
61
 
62
+ if not selected_url:
63
+ return None, f"❌ Found videos, but none were {orientation}. Try another search."
64
+
65
+ # 3. Trim the selected video
66
+ output_filename = f"final_{uuid.uuid4().hex[:8]}.mp4"
67
  ffmpeg_cmd = [
68
+ "ffmpeg", "-ss", str(start_time), "-to", str(end_time),
69
+ "-i", selected_url, "-c:v", "libx264", "-c:a", "aac", "-y", output_filename
 
 
 
 
 
 
 
70
  ]
71
 
 
72
  if end_time <= 0:
73
+ ffmpeg_cmd.pop(3); ffmpeg_cmd.pop(3)
 
74
 
75
  subprocess.run(ffmpeg_cmd, check=True)
76
+ return output_filename, f"βœ… Match found! ({orientation})"
77
 
 
 
 
 
78
  except Exception as e:
79
+ return None, f"❌ Error: {str(e)}"
80
 
81
  # --- Gradio UI ---
82
  with gr.Blocks(theme=gr.themes.Soft()) as demo:
83
+ gr.Markdown("# πŸ“Œ Pinterest Search + Orientation Filter")
84
 
85
  with gr.Row():
86
  with gr.Column():
87
+ query_input = gr.Textbox(label="Search Query", placeholder="Minecraft, Nature, etc.")
88
+ filter_input = gr.Dropdown(choices=["Any", "Portrait", "Landscape"], value="Any", label="Orientation Filter")
89
+
90
  with gr.Row():
91
+ start_input = gr.Number(label="Start (sec)", value=0)
92
+ end_input = gr.Number(label="End (sec, 0=full)", value=0)
93
+
94
+ btn = gr.Button("πŸš€ Find & Process", variant="primary")
95
 
96
  with gr.Column():
97
+ video_output = gr.Video(label="Result")
98
  status_output = gr.Textbox(label="Status")
99
 
100
+ btn.click(process_video, [query_input, filter_input, start_input, end_input], [video_output, status_output])
 
 
 
 
101
 
102
+ demo.launch()