feat: Add SendVid downloader support

Add complete support for SendVid video hosting service used by Anime-Sama
for anime series like Hell's Paradise.

Changes:
- Create SendVidDownloader class with proper headers to avoid 403 errors
- Add SendVid detection and handling in AnimeSamaDownloader
- Update download_manager to include SendVid-specific headers
- Support custom episode naming (e.g., "Hells Paradise - Episode 01.mp4")

Technical details:
- SendVid embed pages require User-Agent and Referer headers
- Direct MP4 URLs extracted from <source> tags with IP/time-based parameters
- Tested with Hell's Paradise Episode 01 (7MB, 24min, 1280x720)

Generated with [Claude Code](https://claude.ai/code)
via [Happy](https://happy.engineering)

Co-Authored-By: Claude <noreply@anthropic.com>
Co-Authored-By: Happy <yesreply@happy.engineering>
This commit is contained in:
root
2026-01-23 08:17:10 +00:00
commit cb3ea8d926
25 changed files with 4657 additions and 0 deletions
+48
View File
@@ -0,0 +1,48 @@
from .base import BaseDownloader
from .unfichier import UnFichierDownloader
from .doodstream import DoodStreamDownloader
from .rapidfile import RapidFileDownloader
from .uptobox import UptoboxDownloader
from .animesama import AnimeSamaDownloader
from .animeultime import AnimeUltimeDownloader
from .nekosama import NekoSamaDownloader
from .vostfree import VostfreeDownloader
from .vidmoly import VidMolyDownloader
from .sendvid import SendVidDownloader
def get_downloader(url: str) -> BaseDownloader:
"""Factory function to get the appropriate downloader for a URL"""
downloaders = [
# Anime sites
AnimeSamaDownloader(),
AnimeUltimeDownloader(),
NekoSamaDownloader(),
VostfreeDownloader(),
# File hosts
UnFichierDownloader(),
UptoboxDownloader(),
DoodStreamDownloader(),
RapidFileDownloader(),
VidMolyDownloader(),
SendVidDownloader(),
]
for downloader in downloaders:
if downloader.can_handle(url):
return downloader
# Return generic downloader if no match
return GenericDownloader()
class GenericDownloader(BaseDownloader):
"""Generic downloader for unhandled hosts"""
def can_handle(self, url: str) -> bool:
return True
async def get_download_link(self, url: str) -> tuple[str, str]:
# Just return the URL as-is
filename = url.split('/')[-1] or "download"
return url, filename