feat: download latest season only + fix lpayer CDN + HLS support
- Watchlist 'Suivre' now downloads only the latest season instead of all episodes - Fix lpayer CDN 403 errors by adding proper Referer header for IP ranges - Add HLS/m3u8 stream download support using ffmpeg - Improve episode filename format: 'Anime - SX - Episode XX.mp4' - Add CDN detection for lpayer IPs (185.237.x.x, 203.188.x.x, /mik/ path)
This commit is contained in:
@@ -489,7 +489,7 @@ class AnimeSamaDownloader(BaseAnimeSite):
|
||||
# Re-raise with clearer message
|
||||
raise Exception(f"Lpayer player not supported - this video host requires manual download. Try another host (VidMoly, SendVid, Sibnet). Error: {str(e)}")
|
||||
|
||||
async def _extract_from_lpayer_api(self, url: str, anime_page_url: str = None, episode_title: str = None) -> tuple[str, str]:
|
||||
async def _extract_from_lpayer_api(self, url: str, anime_page_url: str = None, episode_title: str = None, target_filename: str = None) -> tuple[str, str]:
|
||||
"""Extract video URL from Lplayer using API decryption"""
|
||||
import requests
|
||||
|
||||
@@ -539,13 +539,18 @@ class AnimeSamaDownloader(BaseAnimeSite):
|
||||
|
||||
result = subprocess.run(cmd, capture_output=True, text=True, timeout=30)
|
||||
|
||||
# Use target_filename if provided, otherwise fallback to default
|
||||
filename = target_filename if target_filename else f"lpayer_{video_id}.mp4"
|
||||
|
||||
if result.returncode == 0 and result.stdout:
|
||||
yt_data = json.loads(result.stdout)
|
||||
if 'formats' in yt_data:
|
||||
# Get best mp4 format
|
||||
# Get best mp4 format (highest resolution)
|
||||
formats = yt_data['formats']
|
||||
mp4_formats = [f for f in formats if f.get('ext') == 'mp4']
|
||||
if mp4_formats:
|
||||
# Sort by resolution (height) descending
|
||||
mp4_formats.sort(key=lambda x: x.get('height', 0), reverse=True)
|
||||
video_url = mp4_formats[0].get('url')
|
||||
else:
|
||||
video_url = formats[0].get('url')
|
||||
@@ -553,11 +558,9 @@ class AnimeSamaDownloader(BaseAnimeSite):
|
||||
video_url = yt_data.get('url')
|
||||
|
||||
if video_url:
|
||||
filename = f"lpayer_{video_id}.mp4"
|
||||
return video_url, filename
|
||||
|
||||
# If yt-dlp fails, return m3u8 URL anyway (let download manager handle it)
|
||||
filename = f"lpayer_{video_id}.mp4"
|
||||
return m3u8_url, filename
|
||||
|
||||
async def _extract_from_player(self, player_url: str) -> str | None:
|
||||
@@ -876,11 +879,24 @@ class AnimeSamaDownloader(BaseAnimeSite):
|
||||
try:
|
||||
logger.debug(f"Testing video URL: {url[:60]}...")
|
||||
|
||||
# Build headers with appropriate referer based on URL
|
||||
headers = {"Range": "bytes=0-10240"}
|
||||
|
||||
# Add referer for CDN URLs that require it (lpayer, etc.)
|
||||
if '185.237.' in url or '203.188.' in url or 'lpayer' in url.lower() or '/mik/' in url:
|
||||
headers["Referer"] = "https://lpayer.embed4me.com/"
|
||||
elif 'sibnet.ru' in url:
|
||||
headers["Referer"] = "https://video.sibnet.ru/"
|
||||
elif 'sendvid.com' in url:
|
||||
headers["Referer"] = "https://sendvid.com/"
|
||||
elif 'vidmoly' in url:
|
||||
headers["Referer"] = "https://vidmoly.to/"
|
||||
|
||||
# Stream only first 10KB to validate the URL
|
||||
response = await self.client.get(
|
||||
url,
|
||||
timeout=10.0,
|
||||
headers={"Range": "bytes=0-10240"}
|
||||
headers=headers
|
||||
)
|
||||
|
||||
if response.status_code in (200, 206):
|
||||
@@ -1087,7 +1103,7 @@ class AnimeSamaDownloader(BaseAnimeSite):
|
||||
video_url, anime_page_url, episode_title
|
||||
)
|
||||
elif player_name == 'lpayer':
|
||||
video_url_result, filename = await self._extract_from_lpayer_api(video_url)
|
||||
video_url_result, filename = await self._extract_from_lpayer_api(video_url, anime_page_url, episode_title, target_filename)
|
||||
|
||||
# Validate the extracted URL
|
||||
logger.info(f"Validating extracted URL from {player_name}...")
|
||||
@@ -1494,11 +1510,24 @@ class AnimeSamaDownloader(BaseAnimeSite):
|
||||
try:
|
||||
logger.debug(f"Testing video URL: {url[:60]}...")
|
||||
|
||||
# Build headers with appropriate referer based on URL
|
||||
headers = {"Range": "bytes=0-10240"}
|
||||
|
||||
# Add referer for CDN URLs that require it (lpayer, etc.)
|
||||
if '185.237.' in url or '203.188.' in url or 'lpayer' in url.lower() or '/mik/' in url:
|
||||
headers["Referer"] = "https://lpayer.embed4me.com/"
|
||||
elif 'sibnet.ru' in url:
|
||||
headers["Referer"] = "https://video.sibnet.ru/"
|
||||
elif 'sendvid.com' in url:
|
||||
headers["Referer"] = "https://sendvid.com/"
|
||||
elif 'vidmoly' in url:
|
||||
headers["Referer"] = "https://vidmoly.to/"
|
||||
|
||||
# Stream only first 10KB to validate the URL
|
||||
response = await self.client.get(
|
||||
url,
|
||||
timeout=10.0,
|
||||
headers={"Range": "bytes=0-10240"}
|
||||
headers=headers
|
||||
)
|
||||
|
||||
if response.status_code in (200, 206):
|
||||
@@ -1651,7 +1680,7 @@ class AnimeSamaDownloader(BaseAnimeSite):
|
||||
video_url, anime_page_url, episode_title
|
||||
)
|
||||
elif player_name == 'lpayer':
|
||||
video_url_result, filename = await self._extract_from_lpayer_api(video_url)
|
||||
video_url_result, filename = await self._extract_from_lpayer_api(video_url, anime_page_url, episode_title, target_filename)
|
||||
|
||||
# Validate the extracted URL
|
||||
logger.info(f"Validating extracted URL from {player_name}...")
|
||||
|
||||
Reference in New Issue
Block a user