mirror of
https://github.com/Viren070/MediaFusion.git
synced 2025-12-01 23:21:11 +01:00
Add support for EasyDebrid streaming provider
This commit is contained in:
@@ -39,6 +39,7 @@ class Settings(BaseSettings):
|
||||
"premiumize",
|
||||
"qbittorrent",
|
||||
"stremthru",
|
||||
"easydebrid",
|
||||
]
|
||||
] = Field(default_factory=list)
|
||||
|
||||
|
||||
@@ -142,6 +142,7 @@ class StreamingProvider(BaseModel):
|
||||
"premiumize",
|
||||
"qbittorrent",
|
||||
"stremthru",
|
||||
"easydebrid",
|
||||
] = Field(alias="sv")
|
||||
stremthru_store_name: (
|
||||
Literal[
|
||||
|
||||
@@ -35,6 +35,7 @@ These settings define the basic configuration and identity of your MediaFusion i
|
||||
- "premiumize": Premiumize service
|
||||
- "qbittorrent": qBittorrent client
|
||||
- "stremthru": StremThru service
|
||||
- "easydebrid": EasyDebrid service
|
||||
|
||||
## Database and Cache Settings
|
||||
|
||||
|
||||
@@ -128,6 +128,7 @@ async def get_debrid_cache_metrics() -> Dict[str, Any]:
|
||||
"realdebrid",
|
||||
"seedr",
|
||||
"torbox",
|
||||
"easydebrid",
|
||||
]
|
||||
|
||||
try:
|
||||
|
||||
@@ -100,6 +100,11 @@
|
||||
"label": "AllDebrid",
|
||||
"type": "Premium"
|
||||
},
|
||||
{
|
||||
"value": "easydebrid",
|
||||
"label": "EasyDebrid",
|
||||
"type": "Premium"
|
||||
},
|
||||
{
|
||||
"value": "qbittorrent",
|
||||
"label": "qBittorrent - WebDav",
|
||||
|
||||
@@ -46,6 +46,7 @@
|
||||
<li>🔗 Debrid-Link (Premium)</li>
|
||||
<li>✨ Premiumize (Premium)</li>
|
||||
<li>🏠 AllDebrid (Premium)</li>
|
||||
<li>📦 EasyDebrid (Premium)</li>
|
||||
<li>🔒 qBittorrent - WebDav (Free/Premium)</li>
|
||||
</ul>
|
||||
|
||||
|
||||
@@ -12,6 +12,7 @@ const providerSignupLinks = {
|
||||
debridlink: 'https://debrid-link.com/id/kHgZs',
|
||||
alldebrid: 'https://alldebrid.com/?uid=3ndha&lang=en',
|
||||
torbox: ['https://torbox.app/subscription?referral=339b923e-fb23-40e7-8031-4af39c212e3c', 'https://torbox.app/subscription?referral=e2a28977-99ed-43cd-ba2c-e90dc398c49c', 'https://torbox.app/subscription?referral=38f1c266-8a6c-40b2-a6d2-2148e77dafc9'],
|
||||
easydebrid: 'https://paradise-cloud.com/products/easydebrid',
|
||||
premiumize: 'https://www.premiumize.me',
|
||||
qbittorrent: 'https://github.com/mhdzumair/MediaFusion/tree/main/streaming_providers/qbittorrent#qbittorrent-webdav-setup-options-with-mediafusion',
|
||||
stremthru: 'https://github.com/MunifTanjim/stremthru?tab=readme-ov-file#configuration',
|
||||
|
||||
@@ -0,0 +1,71 @@
|
||||
from typing import Optional
|
||||
|
||||
from streaming_providers.debrid_client import DebridClient
|
||||
from streaming_providers.exceptions import ProviderException
|
||||
|
||||
|
||||
class EasyDebrid(DebridClient):
|
||||
BASE_URL = "https://easydebrid.com/api/v1"
|
||||
|
||||
def __init__(self, token: Optional[str] = None, user_ip: Optional[str] = None):
|
||||
self.user_ip = user_ip
|
||||
super().__init__(token)
|
||||
|
||||
async def initialize_headers(self):
|
||||
self.headers = {"Authorization": f"Bearer {self.token}"}
|
||||
if self.user_ip:
|
||||
self.headers['X-Forwarded-For'] = self.user_ip
|
||||
|
||||
async def disable_access_token(self):
|
||||
pass
|
||||
|
||||
async def __aexit__(self, exc_type, exc_val, exc_tb):
|
||||
await super().__aexit__(exc_type, exc_val, exc_tb)
|
||||
|
||||
async def _handle_service_specific_errors(self, error_data: dict, status_code: int):
|
||||
error_code = error_data.get("error")
|
||||
match error_code:
|
||||
case "Unsupported link for direct download.":
|
||||
raise ProviderException(
|
||||
"Unsupported link for direct download.",
|
||||
"unsupported_direct_download.mp4",
|
||||
)
|
||||
|
||||
async def _make_request(
|
||||
self,
|
||||
method: str,
|
||||
url: str,
|
||||
data: Optional[dict | str] = None,
|
||||
json: Optional[dict] = None,
|
||||
params: Optional[dict] = None,
|
||||
is_return_none: bool = False,
|
||||
is_expected_to_fail: bool = False,
|
||||
retry_count: int = 0,
|
||||
) -> dict:
|
||||
params = params or {}
|
||||
url = self.BASE_URL + url
|
||||
return await super()._make_request(
|
||||
method, url, data, json, params, is_return_none, is_expected_to_fail
|
||||
)
|
||||
|
||||
async def get_torrent_instant_availability(self, urls: list[str]):
|
||||
response = await self._make_request(
|
||||
"POST",
|
||||
"/link/lookup",
|
||||
json={"urls": urls},
|
||||
)
|
||||
return response.get("cached", [])
|
||||
|
||||
async def create_download_link(self, magnet):
|
||||
response = await self._make_request(
|
||||
"POST",
|
||||
"/link/generate",
|
||||
json={"url": magnet},
|
||||
)
|
||||
return response
|
||||
|
||||
async def get_torrent_info(self, torrent_id: str) -> dict:
|
||||
pass
|
||||
|
||||
async def get_user_info(self):
|
||||
return await self._make_request("GET", "/user/details")
|
||||
@@ -0,0 +1,89 @@
|
||||
import asyncio
|
||||
import logging
|
||||
from typing import Any, Dict, List, Optional, Iterator
|
||||
|
||||
from db.models import TorrentStreams
|
||||
from db.schemas import UserData
|
||||
from streaming_providers.exceptions import ProviderException
|
||||
from streaming_providers.parser import select_file_index_from_torrent
|
||||
from streaming_providers.easydebrid.client import EasyDebrid
|
||||
|
||||
|
||||
async def get_video_url_from_easydebrid(
|
||||
magnet_link: str,
|
||||
user_data: UserData,
|
||||
filename: str,
|
||||
user_ip: str,
|
||||
episode: Optional[int] = None,
|
||||
**kwargs: Any,
|
||||
) -> str:
|
||||
async with EasyDebrid(
|
||||
token=user_data.streaming_provider.token,
|
||||
user_ip=user_ip,
|
||||
) as easydebrid_client:
|
||||
torrent_info = await easydebrid_client.create_download_link(magnet_link)
|
||||
file_index = await select_file_index_from_torrent(
|
||||
torrent_info,
|
||||
filename,
|
||||
episode,
|
||||
name_key="filename",
|
||||
)
|
||||
return torrent_info["files"][file_index]["url"]
|
||||
|
||||
|
||||
def divide_chunks(lst: List[Any], n: int) -> Iterator[List[Any]]:
|
||||
"""Yield successive n-sized chunks from lst."""
|
||||
for i in range(0, len(lst), n):
|
||||
yield lst[i : i + n]
|
||||
|
||||
|
||||
async def update_chunk_cache_status(
|
||||
easydebrid_client: EasyDebrid, streams_chunk: List[TorrentStreams]
|
||||
) -> None:
|
||||
"""Update cache status for a chunk of streams."""
|
||||
try:
|
||||
instant_availability_data = (
|
||||
await easydebrid_client.get_torrent_instant_availability(
|
||||
[f"magnet:?xt=urn:btih:{stream.id}" for stream in streams_chunk]
|
||||
)
|
||||
)
|
||||
for stream, instant_availability in zip(
|
||||
streams_chunk, instant_availability_data
|
||||
):
|
||||
stream.cached = instant_availability
|
||||
except ProviderException as e:
|
||||
logging.error(f"Failed to get cached status from easydebrid for a chunk: {e}")
|
||||
|
||||
|
||||
async def update_easydebrid_cache_status(
|
||||
streams: List[TorrentStreams], user_data: UserData, user_ip: str, **kwargs: Any
|
||||
) -> None:
|
||||
"""Updates the cache status of streams based on Easydebrid's instant availability."""
|
||||
async with EasyDebrid(
|
||||
token=user_data.streaming_provider.token,
|
||||
user_ip=user_ip,
|
||||
) as easydebrid_client:
|
||||
chunks = list(divide_chunks(streams, 50))
|
||||
update_tasks = [
|
||||
update_chunk_cache_status(easydebrid_client, chunk) for chunk in chunks
|
||||
]
|
||||
await asyncio.gather(*update_tasks)
|
||||
|
||||
|
||||
async def validate_easydebrid_credentials(
|
||||
user_data: UserData, user_ip: str, **kwargs: Any
|
||||
) -> Dict[str, str]:
|
||||
"""Validates the EasyDebrid credentials."""
|
||||
try:
|
||||
async with EasyDebrid(
|
||||
token=user_data.streaming_provider.token,
|
||||
user_ip=user_ip,
|
||||
) as easydebrid_client:
|
||||
await easydebrid_client.get_user_info()
|
||||
return {"status": "success"}
|
||||
|
||||
except ProviderException as error:
|
||||
return {
|
||||
"status": "error",
|
||||
"message": f"Failed to validate EasyDebrid credentials: {error.message}",
|
||||
}
|
||||
@@ -68,6 +68,11 @@ from streaming_providers.stremthru.utils import (
|
||||
get_video_url_from_stremthru,
|
||||
validate_stremthru_credentials,
|
||||
)
|
||||
from streaming_providers.easydebrid.utils import (
|
||||
update_easydebrid_cache_status,
|
||||
get_video_url_from_easydebrid,
|
||||
validate_easydebrid_credentials,
|
||||
)
|
||||
|
||||
# Define provider-specific cache update functions
|
||||
CACHE_UPDATE_FUNCTIONS = {
|
||||
@@ -81,6 +86,7 @@ CACHE_UPDATE_FUNCTIONS = {
|
||||
"premiumize": update_pm_cache_status,
|
||||
"qbittorrent": update_qbittorrent_cache_status,
|
||||
"stremthru": update_st_cache_status,
|
||||
"easydebrid": update_easydebrid_cache_status,
|
||||
}
|
||||
|
||||
# Define provider-specific downloaded info hashes fetch functions
|
||||
@@ -123,6 +129,7 @@ GET_VIDEO_URL_FUNCTIONS = {
|
||||
"seedr": get_video_url_from_seedr,
|
||||
"torbox": get_video_url_from_torbox,
|
||||
"stremthru": get_video_url_from_stremthru,
|
||||
"easydebrid": get_video_url_from_easydebrid,
|
||||
}
|
||||
|
||||
|
||||
@@ -137,4 +144,5 @@ VALIDATE_CREDENTIALS_FUNCTIONS = {
|
||||
"seedr": validate_seedr_credentials,
|
||||
"torbox": validate_torbox_credentials,
|
||||
"stremthru": validate_stremthru_credentials,
|
||||
"easydebrid": validate_easydebrid_credentials,
|
||||
}
|
||||
|
||||
@@ -183,6 +183,7 @@ STREAMING_PROVIDERS_SHORT_NAMES = {
|
||||
"seedr": "SDR",
|
||||
"torbox": "TRB",
|
||||
"stremthru": "ST",
|
||||
"easydebrid": "ED",
|
||||
}
|
||||
|
||||
CERTIFICATION_MAPPING = {
|
||||
|
||||
Reference in New Issue
Block a user