Skip to content

Commit

Permalink
feat: easydebrid support
Browse files Browse the repository at this point in the history
  • Loading branch information
g0ldyy committed Nov 27, 2024
1 parent 730c683 commit 15b22e7
Show file tree
Hide file tree
Showing 6 changed files with 232 additions and 19 deletions.
21 changes: 8 additions & 13 deletions comet/api/stream.py
Original file line number Diff line number Diff line change
Expand Up @@ -147,7 +147,7 @@ async def stream(
config["debridApiKey"] = settings.PROXY_DEBRID_STREAM_DEBRID_DEFAULT_APIKEY

if config["debridApiKey"] == "":
services = ["realdebrid", "alldebrid", "premiumize", "torbox", "debridlink"]
services = ["realdebrid", "alldebrid", "premiumize", "torbox", "debridlink", "easydebrid"]
debrid_emoji = "⬇️"
else:
services = [config["debridService"]]
Expand Down Expand Up @@ -445,17 +445,6 @@ async def stream(
)

if len_sorted_ranked_files == 0:
if config["debridApiKey"] == "realdebrid":
return {
"streams": [
{
"name": "[⚠️] Comet",
"description": "RealDebrid API is unstable!",
"url": "https://comet.fast",
}
]
}

return {"streams": []}

sorted_ranked_files = {
Expand All @@ -470,8 +459,14 @@ async def stream(
sorted_ranked_files[hash]["data"]["tracker"] = torrents_by_hash[hash][
"Tracker"
]
sorted_ranked_files[hash]["data"]["size"] = files[hash]["size"]
torrent_size = torrents_by_hash[hash]["Size"]
sorted_ranked_files[hash]["data"]["size"] = (
files[hash]["size"]
if config["debridService"] != "easydebrid"
else torrent_size
if torrent_size
else 0
)
sorted_ranked_files[hash]["data"]["torrent_size"] = (
torrent_size if torrent_size else files[hash]["size"]
)
Expand Down
178 changes: 178 additions & 0 deletions comet/debrid/easydebrid.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,178 @@
import aiohttp
import asyncio

from RTN import parse

from comet.utils.general import is_video
from comet.utils.logger import logger


class EasyDebrid:
def __init__(self, session: aiohttp.ClientSession, debrid_api_key: str, ip: str):
self.session = session
self.ip = ip
self.proxy = None

self.api_url = "https://easydebrid.com/api/v1"
self.headers = {"Authorization": f"Bearer {debrid_api_key}"}

if ip:
self.headers["X-Forwarded-For"] = ip

async def check_premium(self):
try:
response = await self.session.get(
f"{self.api_url}/user/details", headers=self.headers
)
data = await response.json()
return bool(data["paid_until"])
except Exception as e:
logger.warning(f"Failed to check EasyDebrid premium status: {e}")

return False

async def get_instant(self, chunk):
try:
response = await self.session.post(
f"{self.api_url}/link/lookup",
json={"urls": chunk},
headers=self.headers,
)
data = await response.json()

if not data or "cached" not in data:
return None

return {
"status": "success",
"response": data["cached"],
"filename": data.get("filenames", []),
"filesize": [None] * len(chunk),
"hashes": chunk,
}
except Exception as e:
logger.warning(
f"Exception while checking hash instant availability on EasyDebrid: {e}"
)

async def get_files(self, torrent_hashes, type, season, episode, kitsu):
chunk_size = 100
chunks = [
torrent_hashes[i : i + chunk_size]
for i in range(0, len(torrent_hashes), chunk_size)
]

tasks = []
for chunk in chunks:
tasks.append(self.get_instant(chunk))

responses = await asyncio.gather(*tasks)

files = {}

if type == "series":
for result in responses:
if result["status"] != "success":
continue

responses = result["response"]
filenames = result["filename"]
hashes = result["hashes"]

for index, (is_cached, hash) in enumerate(zip(responses, hashes)):
if not is_cached:
continue

hash_files = filenames[index]

for filename in hash_files:
if not is_video(filename):
continue

if "sample" in filename.lower():
continue

filename_parsed = parse(filename)
if not filename_parsed:
continue

if episode not in filename_parsed.episodes:
continue

if kitsu:
if filename_parsed.seasons:
continue
elif season not in filename_parsed.seasons:
continue

files[hash] = {
"index": f"{season}|{episode}",
"title": filename,
"size": 0, # Size not available in lookup response
}
break # Found matching video file
else:
for result in responses:
if result["status"] != "success":
continue

responses = result["response"]
filenames = result["filename"]
hashes = result["hashes"]

for index, (is_cached, hash) in enumerate(zip(responses, hashes)):
if not is_cached:
continue

hash_files = filenames[index]

video_files = [f for f in hash_files if is_video(f)]
if not video_files:
continue

# Use first valid video file found
files[hash] = {
"index": 0,
"title": video_files[0],
"size": 0, # Size not available in lookup response
}

return files

async def generate_download_link(self, hash, index):
try:
response = await self.session.post(
f"{self.api_url}/link/generate",
headers={**self.headers, "Content-Type": "application/json"},
json={"url": f"magnet:?xt=urn:btih:{hash}"},
)
data = await response.json()

if not data or "files" not in data:
return None

video_files = [
f
for f in data["files"]
if is_video(f["filename"]) and "sample" not in f["filename"].lower()
]

if not video_files:
return None

if "|" in str(index):
season, episode = map(int, index.split("|"))
for file in video_files:
parsed = parse(file["filename"])
if (
parsed
and season in parsed.seasons
and episode in parsed.episodes
):
return file["url"]

largest_file = max(video_files, key=lambda x: x["size"])

return largest_file["url"]
except Exception as e:
logger.warning(f"Error generating link for {hash}|{index}: {e}")
3 changes: 3 additions & 0 deletions comet/debrid/manager.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
from .premiumize import Premiumize
from .torbox import TorBox
from .debridlink import DebridLink
from .easydebrid import EasyDebrid


def getDebrid(session: aiohttp.ClientSession, config: dict, ip: str):
Expand All @@ -20,3 +21,5 @@ def getDebrid(session: aiohttp.ClientSession, config: dict, ip: str):
return TorBox(session, debrid_api_key)
elif debrid_service == "debridlink":
return DebridLink(session, debrid_api_key)
elif debrid_service == "easydebrid":
return EasyDebrid(session, debrid_api_key, ip)
25 changes: 22 additions & 3 deletions comet/templates/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -540,9 +540,10 @@
</div>

<div class="form-item">
<sl-select id="debridService" value="debridlink" label="Debrid Service" placeholder="Select debrid service">
<sl-option value="debridlink">Debrid-Link</sl-option>
<sl-select id="debridService" value="torbox" label="Debrid Service" placeholder="Select debrid service">
<sl-option value="torbox">TorBox</sl-option>
<sl-option value="easydebrid">EasyDebrid</sl-option>
<sl-option value="debridlink">Debrid-Link</sl-option>
<sl-option value="alldebrid">All-Debrid</sl-option>
<sl-option value="premiumize">Premiumize</sl-option>
<sl-option value="realdebrid">Real-Debrid</sl-option>
Expand All @@ -552,7 +553,9 @@
<div class="form-item">
<label for="debridService">
Debrid API Key -
<a id="apiKeyLink" href="https://debrid-link.com/webapp/apikey" target="_blank">Get It Here</a>
<a id="apiKeyLink" href="https://torbox.app/settings" target="_blank">Get It Here</a>
<a id="support"></a>
<a id="warning" href="https://rentry.co/easydebrid" target="_blank"></a>
</label>
<sl-input id="debridApiKey" placeholder="Enter API key" help-text="If no key is specified, you'll get direct torrents!"></sl-input>
</div>
Expand All @@ -570,17 +573,33 @@
document.getElementById("debridService").addEventListener("sl-change", function(event) {
const selectedService = event.target.value;
const apiKeyLink = document.getElementById("apiKeyLink");
support = document.getElementById("support");
warning = document.getElementById("warning");

if (selectedService === "realdebrid") {
apiKeyLink.href = "https://real-debrid.com/apitoken";
support.textContent = "";
warning.textContent = "";
} else if (selectedService === "alldebrid") {
apiKeyLink.href = "https://alldebrid.com/apikeys";
support.textContent = "";
warning.textContent = "";
} else if (selectedService === "premiumize") {
apiKeyLink.href = "https://premiumize.me/account";
support.textContent = "";
warning.textContent = "";
} else if (selectedService === "torbox") {
apiKeyLink.href = "https://torbox.app/settings";
support.textContent = "";
warning.textContent = "";
} else if (selectedService === "debridlink") {
apiKeyLink.href = "https://debrid-link.com/webapp/apikey";
support.textContent = "";
warning.textContent = "";
} else if (selectedService === "easydebrid") {
apiKeyLink.href = "https://paradise-cloud.com/products/easydebrid";
support.textContent = " - Support me by using promo code 'goldy'! (5% OFF) - ";
warning.textContent = "warning";
}
});
</script>
Expand Down
22 changes: 20 additions & 2 deletions comet/utils/general.py
Original file line number Diff line number Diff line change
Expand Up @@ -234,6 +234,22 @@ def bytes_to_size(bytes: int):
return f"{round(bytes, 2)} {sizes[i]}"


def size_to_bytes(size_str: str):
sizes = ["bytes", "kb", "mb", "gb", "tb"]
try:
value, unit = size_str.split()
value = float(value)
unit = unit.lower()

if unit not in sizes:
return None

multiplier = 1024 ** sizes.index(unit)
return int(value * multiplier)
except:
return None


def config_check(b64config: str):
try:
config = orjson.loads(base64.b64decode(b64config).decode())
Expand All @@ -253,6 +269,7 @@ def get_debrid_extension(debridService: str, debridApiKey: str = None):
"premiumize": "PM",
"torbox": "TB",
"debridlink": "DL",
"easydebrid": "ED",
}

return debrid_extensions.get(debridService, None)
Expand Down Expand Up @@ -355,7 +372,7 @@ async def get_zilean(
object = {
"Title": result["raw_title"],
"InfoHash": result["info_hash"],
"Size": result["size"],
"Size": int(result["size"]),
"Tracker": "DMM",
}

Expand Down Expand Up @@ -391,12 +408,13 @@ async def get_torrentio(log_name: str, type: str, full_id: str):
title_full = torrent["title"]
title = title_full.split("\n")[0]
tracker = title_full.split("⚙️ ")[1].split("\n")[0]
size = size_to_bytes(title_full.split("💾 ")[1].split(" ⚙️")[0])

results.append(
{
"Title": title,
"InfoHash": torrent["infoHash"],
"Size": None,
"Size": size,
"Tracker": f"Torrentio|{tracker}",
}
)
Expand Down
2 changes: 1 addition & 1 deletion comet/utils/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -123,7 +123,7 @@ def check_max_size(cls, v):

@field_validator("debridService")
def check_debrid_service(cls, v):
if v not in ["realdebrid", "alldebrid", "premiumize", "torbox", "debridlink"]:
if v not in ["realdebrid", "alldebrid", "premiumize", "torbox", "debridlink", "easydebrid"]:
raise ValueError("Invalid debridService")
return v

Expand Down

0 comments on commit 15b22e7

Please sign in to comment.