Deepfake Authenticator commited on
Commit
20dd477
Β·
1 Parent(s): 6c71866

fix: yt-dlp filename mismatch in analyze-url endpoint

Browse files

- Use prefix + .%(ext)s template so yt-dlp appends its own extension
- Glob search for created file across .mp4/.webm/.mkv/.avi/.mov
- Second glob fallback catches any yt-dlp naming scheme
- Clean up all prefix-matching files in finally block
- Fixes 'Unsupported file type' error from extension

Files changed (1) hide show
  1. backend/main.py +40 -15
backend/main.py CHANGED
@@ -85,49 +85,70 @@ async def analyze_from_url(payload: dict):
85
  if not video_url:
86
  raise HTTPException(status_code=400, detail="No URL provided")
87
 
88
- tmp_path = UPLOAD_DIR / f"ext_{uuid.uuid4().hex}.mp4"
 
 
89
  downloaded = False
90
 
91
  try:
92
- # Try yt-dlp first (YouTube, Twitter, Instagram, TikTok, etc.)
93
  try:
94
  import yt_dlp
95
  ydl_opts = {
96
  "format": "bestvideo[ext=mp4][height<=720]+bestaudio[ext=m4a]/best[ext=mp4][height<=720]/best",
97
- "outtmpl": str(tmp_path),
98
  "quiet": True,
99
  "no_warnings": True,
100
  "merge_output_format": "mp4",
101
  }
102
  with yt_dlp.YoutubeDL(ydl_opts) as ydl:
103
  ydl.download([video_url])
104
- downloaded = tmp_path.exists() and tmp_path.stat().st_size > 1000
105
- if downloaded:
106
- logger.info(f"yt-dlp downloaded {tmp_path.stat().st_size // 1024}KB")
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
107
  except ImportError:
108
  logger.info("yt-dlp not installed β€” trying direct HTTP fetch")
109
  except Exception as e:
110
  logger.warning(f"yt-dlp failed ({e}) β€” trying direct fetch")
111
 
112
- # Fallback: direct HTTP fetch for plain .mp4/.webm URLs
113
  if not downloaded:
114
  try:
115
  import httpx
 
116
  async with httpx.AsyncClient(timeout=60, follow_redirects=True) as client:
117
  r = await client.get(video_url, headers={"User-Agent": "Mozilla/5.0"})
118
- if r.status_code == 200:
119
- tmp_path.write_bytes(r.content)
120
- downloaded = tmp_path.exists() and tmp_path.stat().st_size > 1000
 
121
  except Exception as e:
122
  logger.warning(f"Direct fetch failed: {e}")
123
 
124
- if not downloaded:
125
  raise HTTPException(
126
  status_code=400,
127
- detail="Could not download video. For YouTube, install yt-dlp: pip install yt-dlp"
128
  )
129
 
130
- result = authenticator.analyze(str(tmp_path))
 
131
  return result
132
 
133
  except HTTPException:
@@ -136,8 +157,12 @@ async def analyze_from_url(payload: dict):
136
  logger.exception(f"analyze-url failed: {e}")
137
  raise HTTPException(status_code=500, detail=str(e))
138
  finally:
139
- if tmp_path.exists():
140
- tmp_path.unlink()
 
 
 
 
141
 
142
 
143
  @app.post("/analyze")
 
85
  if not video_url:
86
  raise HTTPException(status_code=400, detail="No URL provided")
87
 
88
+ # Use a unique prefix β€” yt-dlp appends its own extension
89
+ tmp_prefix = UPLOAD_DIR / f"ext_{uuid.uuid4().hex}"
90
+ actual_path = None
91
  downloaded = False
92
 
93
  try:
94
+ # ── yt-dlp: handles YouTube, Twitter, Instagram, TikTok ─────────────
95
  try:
96
  import yt_dlp
97
  ydl_opts = {
98
  "format": "bestvideo[ext=mp4][height<=720]+bestaudio[ext=m4a]/best[ext=mp4][height<=720]/best",
99
+ "outtmpl": str(tmp_prefix) + ".%(ext)s", # yt-dlp adds extension
100
  "quiet": True,
101
  "no_warnings": True,
102
  "merge_output_format": "mp4",
103
  }
104
  with yt_dlp.YoutubeDL(ydl_opts) as ydl:
105
  ydl.download([video_url])
106
+
107
+ # Find whatever file yt-dlp created
108
+ for ext in (".mp4", ".webm", ".mkv", ".avi", ".mov"):
109
+ candidate = Path(str(tmp_prefix) + ext)
110
+ if candidate.exists() and candidate.stat().st_size > 1000:
111
+ actual_path = candidate
112
+ downloaded = True
113
+ logger.info(f"yt-dlp: {actual_path.name} ({actual_path.stat().st_size // 1024}KB)")
114
+ break
115
+
116
+ # Glob fallback in case yt-dlp used a different naming scheme
117
+ if not downloaded:
118
+ for f in sorted(UPLOAD_DIR.glob(f"{tmp_prefix.name}*")):
119
+ if f.stat().st_size > 1000:
120
+ actual_path = f
121
+ downloaded = True
122
+ logger.info(f"yt-dlp (glob): {actual_path.name}")
123
+ break
124
+
125
  except ImportError:
126
  logger.info("yt-dlp not installed β€” trying direct HTTP fetch")
127
  except Exception as e:
128
  logger.warning(f"yt-dlp failed ({e}) β€” trying direct fetch")
129
 
130
+ # ── Fallback: direct HTTP fetch for plain video URLs ─────────────────
131
  if not downloaded:
132
  try:
133
  import httpx
134
+ actual_path = Path(str(tmp_prefix) + ".mp4")
135
  async with httpx.AsyncClient(timeout=60, follow_redirects=True) as client:
136
  r = await client.get(video_url, headers={"User-Agent": "Mozilla/5.0"})
137
+ if r.status_code == 200 and len(r.content) > 1000:
138
+ actual_path.write_bytes(r.content)
139
+ downloaded = True
140
+ logger.info(f"Direct fetch: {len(r.content) // 1024}KB")
141
  except Exception as e:
142
  logger.warning(f"Direct fetch failed: {e}")
143
 
144
+ if not downloaded or actual_path is None:
145
  raise HTTPException(
146
  status_code=400,
147
+ detail="Could not download video. For YouTube, ensure yt-dlp is installed: pip install yt-dlp"
148
  )
149
 
150
+ # Analyze β€” no file extension check needed here (yt-dlp handles format)
151
+ result = authenticator.analyze(str(actual_path))
152
  return result
153
 
154
  except HTTPException:
 
157
  logger.exception(f"analyze-url failed: {e}")
158
  raise HTTPException(status_code=500, detail=str(e))
159
  finally:
160
+ # Clean up all files with our prefix
161
+ for f in UPLOAD_DIR.glob(f"{tmp_prefix.name}*"):
162
+ try:
163
+ f.unlink()
164
+ except Exception:
165
+ pass
166
 
167
 
168
  @app.post("/analyze")