diff --git a/.env-sample b/.env-sample
index d257864..af7c718 100644
--- a/.env-sample
+++ b/.env-sample
@@ -13,4 +13,7 @@ INDEXER_MANAGER_TIMEOUT=60 # maximum time to obtain search results from indexer
INDEXER_MANAGER_INDEXERS='["EXAMPLE1_CHANGETHIS", "EXAMPLE2_CHANGETHIS"]'
GET_TORRENT_TIMEOUT=5 # maximum time to obtain the torrent info hash in seconds
ZILEAN_URL=None # for DMM search - https://github.com/iPromKnight/zilean
-CUSTOM_HEADER_HTML=None # only set it if you know what it is
\ No newline at end of file
+CUSTOM_HEADER_HTML=None # only set it if you know what it is
+PROXY_DEBRID_STREAM=False # Proxy Debrid Streams (very useful to use your debrid service on multiple IPs at same time)
+PROXY_DEBRID_STREAM_PASSWORD=CHANGE_ME # Secret password to enter on configuration page to prevent people from abusing your debrid stream proxy
+PROXY_DEBRID_STREAM_BYTES_PER_CHUNK=102400 # 10MB per chunks
\ No newline at end of file
diff --git a/comet/api/stream.py b/comet/api/stream.py
index 6318188..3654ed8 100644
--- a/comet/api/stream.py
+++ b/comet/api/stream.py
@@ -5,7 +5,7 @@ import time
import aiohttp
from fastapi import APIRouter, Request
-from fastapi.responses import RedirectResponse
+from fastapi.responses import RedirectResponse, StreamingResponse
from RTN import Torrent, parse, sort_torrents, title_match
from comet.debrid.manager import getDebrid
@@ -279,7 +279,7 @@ async def playback(b64config: str, hash: str, index: str):
@streams.get("/{b64config}/playback/{hash}/{index}")
-async def playback(b64config: str, hash: str, index: str):
+async def playback(request: Request, b64config: str, hash: str, index: str):
config = config_check(b64config)
if not config:
return
@@ -288,4 +288,46 @@ async def playback(b64config: str, hash: str, index: str):
debrid = getDebrid(session, config)
download_link = await debrid.generate_download_link(hash, index)
- return RedirectResponse(download_link, status_code=302)
+ if (
+ settings.PROXY_DEBRID_STREAM
+ and settings.PROXY_DEBRID_STREAM_PASSWORD
+ == config["debridStreamProxyPassword"]
+ ):
+
+ async def stream_content(headers: dict):
+ async with aiohttp.ClientSession() as session:
+ response = await session.get(download_link, headers=headers)
+ while True:
+ chunk = await response.content.read(
+ settings.PROXY_DEBRID_STREAM_BYTES_PER_CHUNK
+ ) # 10 MB chunks
+ if not chunk:
+ break
+ yield chunk
+
+ range = None
+ range_header = request.headers.get("range")
+ if range_header:
+ range_value = range_header.strip().split("=")[1]
+ start, end = range_value.split("-")
+ start = int(start)
+ end = int(end) if end else ""
+ range = f"bytes={start}-{end}"
+
+ response = await session.get(
+ download_link, headers={"Range": f"bytes={start}-{end}"}
+ )
+ if response.status == 206:
+ return StreamingResponse(
+ stream_content({"Range": range}),
+ status_code=206,
+ headers={
+ "Content-Range": response.headers["Content-Range"],
+ "Content-Length": response.headers["Content-Length"],
+ "Accept-Ranges": "bytes",
+ },
+ )
+
+ return
+
+ return RedirectResponse(download_link, status_code=302)
diff --git a/comet/debrid/manager.py b/comet/debrid/manager.py
index aa30333..cd1cc4a 100644
--- a/comet/debrid/manager.py
+++ b/comet/debrid/manager.py
@@ -7,4 +7,4 @@ def getDebrid(session: aiohttp.ClientSession, config: dict):
debrid_service = config["debridService"]
debrid_api_key = config["debridApiKey"]
if debrid_service == "realdebrid":
- return RealDebrid(session, debrid_api_key)
\ No newline at end of file
+ return RealDebrid(session, debrid_api_key)
diff --git a/comet/debrid/realdebrid.py b/comet/debrid/realdebrid.py
index 2e43b6e..a79b4da 100644
--- a/comet/debrid/realdebrid.py
+++ b/comet/debrid/realdebrid.py
@@ -16,9 +16,7 @@ class RealDebrid:
async def check_premium(self):
try:
- check_premium = await self.session.get(
- f"{self.api_url}/user"
- )
+ check_premium = await self.session.get(f"{self.api_url}/user")
check_premium = await check_premium.text()
if '"type": "premium"' not in check_premium:
return False
@@ -29,7 +27,7 @@ class RealDebrid:
f"Exception while checking premium status on Real Debrid: {e}"
)
return False
-
+
async def get_instant(self, hash: str):
try:
response = await self.session.get(
@@ -58,7 +56,6 @@ class RealDebrid:
return availability
-
async def get_files(self, availability: dict, type: str, season: str, episode: str):
files = {}
for hash, details in availability.items():
diff --git a/comet/templates/index.html b/comet/templates/index.html
index 78c88a9..32c3434 100644
--- a/comet/templates/index.html
+++ b/comet/templates/index.html
@@ -514,6 +514,10 @@