Skip to content

Commit 0888ae2

Browse files
author
shiey
committed
Enhance fb.watch URL support with improved redirect handling
✨ Improvements: - Enhanced redirect resolution with multiple hop support - Better error messages specifically for fb.watch URLs - Added comprehensive URL format documentation to README - Improved headers and timeout handling for redirects - Added pro tips for mobile users with fb.watch links 🔧 Technical Changes: - Enhanced _resolve_fb_watch_url() with proper redirect chain handling - Added relative URL handling for redirects - Improved error messages with actionable guidance - Added URL format examples and troubleshooting tips 📚 Documentation: - Added 'Supported URL Formats' section to README - Included fb.watch troubleshooting guide - Added mobile user guidance for redirect URLs
1 parent 15bf926 commit 0888ae2

2 files changed

Lines changed: 111 additions & 20 deletions

File tree

README.md

Lines changed: 48 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -101,7 +101,54 @@ This isn't just another video downloader. It's the result of:
101101
102102
---
103103

104-
## 📚 Complete Documentation Suite
104+
## � Supported URL Formats
105+
106+
*"We speak all dialects of Facebook!"* 🗣️
107+
108+
Our service supports **all major Facebook URL formats**, including the tricky ones:
109+
110+
### **Standard Facebook URLs**
111+
```
112+
https://www.facebook.com/watch/?v=1234567890
113+
https://facebook.com/username/videos/1234567890
114+
https://www.facebook.com/video.php?v=1234567890
115+
https://web.facebook.com/watch/?v=1234567890
116+
```
117+
118+
### **Mobile Facebook URLs**
119+
```
120+
https://m.facebook.com/watch/?v=1234567890
121+
https://m.facebook.com/story.php?story_fbid=...
122+
```
123+
124+
### **Facebook Reels**
125+
```
126+
https://www.facebook.com/reel/1234567890
127+
https://facebook.com/username/videos/1234567890 (Reels)
128+
```
129+
130+
### **Short URLs (fb.watch)**
131+
```
132+
https://fb.watch/BFC-iErR4Y/
133+
https://fb.watch/ABC123def/
134+
```
135+
136+
### 💡 **Pro Tips for fb.watch URLs**
137+
138+
*fb.watch* URLs are mobile-friendly short links, but they can be a bit finicky:
139+
140+
- **✅ Best Practice**: If a fb.watch URL doesn't work, follow these steps:
141+
1. **Open the fb.watch link** in your browser
142+
2. **Copy the full URL** from the address bar (should be facebook.com/...)
143+
3. **Use that URL instead** - it'll work perfectly!
144+
145+
- **🎯 Why?** fb.watch URLs are redirects, and sometimes they get lost in translation. The full Facebook URL is always more reliable!
146+
147+
- **📱 Mobile Users**: When you share a video from the Facebook app, you often get fb.watch URLs. Just follow the steps above for best results!
148+
149+
---
150+
151+
## �📚 Complete Documentation Suite
105152

106153
We believe in documentation more than we believe in coffee ☕ (and that's saying something!):
107154

app/services/video_service.py

Lines changed: 63 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -66,25 +66,63 @@ async def get_video_info(self, url: str, quality: VideoQuality = VideoQuality.BE
6666
raise ValueError(f"Failed to extract video information: {str(e)}")
6767

6868
async def _resolve_fb_watch_url(self, url: str) -> str:
69-
"""Resolve fb.watch URLs to full Facebook URLs"""
69+
"""Resolve fb.watch URLs to full Facebook URLs with multiple redirect handling"""
7070
import aiohttp
7171

7272
try:
73-
timeout = aiohttp.ClientTimeout(total=10)
73+
timeout = aiohttp.ClientTimeout(total=15)
74+
headers = {
75+
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36',
76+
'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8',
77+
'Accept-Language': 'en-US,en;q=0.5',
78+
'Accept-Encoding': 'gzip, deflate',
79+
'Connection': 'keep-alive',
80+
'Upgrade-Insecure-Requests': '1',
81+
}
82+
7483
async with aiohttp.ClientSession(timeout=timeout) as session:
75-
# Follow redirects manually to get the final URL
76-
async with session.get(
77-
url,
78-
allow_redirects=False,
79-
headers={
80-
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36'
81-
}
82-
) as response:
83-
if response.status in [301, 302, 303, 307, 308]:
84-
redirect_url = response.headers.get('Location', url)
85-
if 'facebook.com' in redirect_url:
86-
return redirect_url
87-
return url
84+
current_url = url
85+
max_redirects = 5
86+
redirect_count = 0
87+
88+
while redirect_count < max_redirects:
89+
try:
90+
async with session.get(
91+
current_url,
92+
allow_redirects=False,
93+
headers=headers
94+
) as response:
95+
# If it's a redirect response
96+
if response.status in [301, 302, 303, 307, 308]:
97+
redirect_url = response.headers.get('Location')
98+
if redirect_url:
99+
# Handle relative redirects
100+
if redirect_url.startswith('/'):
101+
from urllib.parse import urljoin
102+
redirect_url = urljoin(current_url, redirect_url)
103+
104+
# Check if we got a Facebook URL
105+
if 'facebook.com' in redirect_url:
106+
logger.info(f"Resolved fb.watch URL: {url} -> {redirect_url}")
107+
return redirect_url
108+
109+
current_url = redirect_url
110+
redirect_count += 1
111+
else:
112+
break
113+
else:
114+
# No more redirects, check if current URL is Facebook
115+
if 'facebook.com' in current_url:
116+
return current_url
117+
break
118+
except Exception as e:
119+
logger.warning(f"Error during redirect {redirect_count}: {str(e)}")
120+
break
121+
122+
# If we couldn't resolve to a facebook.com URL, return original
123+
logger.warning(f"Could not resolve fb.watch URL to facebook.com: {url}")
124+
return url
125+
88126
except Exception as e:
89127
logger.warning(f"Could not resolve fb.watch URL: {str(e)}, using original")
90128
return url
@@ -119,8 +157,11 @@ def _extract_info(self, url: str, quality: VideoQuality) -> Dict[str, Any]:
119157

120158
except yt_dlp.DownloadError as e:
121159
error_msg = str(e)
122-
if "redirect loop" in error_msg.lower():
123-
raise ValueError("Video URL has redirect issues. Try copying the direct Facebook video URL instead of using fb.watch links.")
160+
if "redirect loop" in error_msg.lower() or "redirect" in error_msg.lower():
161+
if 'fb.watch' in url:
162+
raise ValueError("fb.watch URL couldn't be processed. Please try: 1) Open the video on Facebook, 2) Copy the full facebook.com URL from the address bar, 3) Use that URL instead.")
163+
else:
164+
raise ValueError("Video URL has redirect issues. Try copying the direct Facebook video URL.")
124165
elif "private" in error_msg.lower() or "not available" in error_msg.lower():
125166
raise ValueError("This video is private or not available for download.")
126167
elif "age" in error_msg.lower():
@@ -129,8 +170,11 @@ def _extract_info(self, url: str, quality: VideoQuality) -> Dict[str, Any]:
129170
raise ValueError(f"Could not extract video: {error_msg}")
130171
except Exception as e:
131172
error_msg = str(e)
132-
if "302" in error_msg:
133-
raise ValueError("URL redirect issue. Please try using the direct Facebook video URL instead of fb.watch.")
173+
if "302" in error_msg or "redirect" in error_msg.lower():
174+
if 'fb.watch' in url:
175+
raise ValueError("fb.watch URL needs the full Facebook URL. Please: 1) Open the video on Facebook, 2) Copy the complete facebook.com URL, 3) Try again.")
176+
else:
177+
raise ValueError("URL redirect issue. Please try using the direct Facebook video URL.")
134178
else:
135179
raise ValueError(f"Unexpected error: {error_msg}")
136180

0 commit comments

Comments
 (0)