Fix jdownloader subfolder structure!

Signed-off-by: anasty17 <e.anastayyar@gmail.com>
This commit is contained in:
anasty17 2024-01-09 06:46:14 +02:00
parent eeb5bf2c85
commit 59cc026843
11 changed files with 1732 additions and 103 deletions

View File

@ -165,7 +165,7 @@ MIRROR_HELP_DICT = {
"DL-Auth": "<b>Direct link authorization</b>: -au -ap\n\n/cmd link -au username -ap password",
"Headers": "<b>Direct link custom headers</b>: -h\n\n/cmd link -h key: value key1: value1",
"Extract/Zip": extract_zip,
"Torrent-Files": "<b>Bittorrent File Selection</b>: -s\n\n/cmd link -s or by replying to file/link",
"Torrent-Files": "<b>Bittorrent/JDownloader File Selection</b>: -s\n\n/cmd link -s or by replying to file/link",
"Torrent-Seed": seed,
"Multi-Link": multi_link,
"Same-Directory": same_dir,

View File

@ -1,9 +1,9 @@
from myjdapi import Myjdapi
from myjd import Myjdapi
from json import dump
from asyncio import sleep as aiosleep
from random import randint
from aiofiles.os import listdir
from myjdapi.exception import (
from myjd.exception import (
MYJDException,
MYJDAuthFailedException,
MYJDEmailForbiddenException,
@ -117,7 +117,7 @@ class JDownloader(Myjdapi):
@new_task
async def keepJdAlive(self):
while True:
await aiosleep(100)
await aiosleep(300)
if self.device is None:
break
async with jd_lock:

View File

@ -17,12 +17,12 @@ async def _onDownloadComplete(gid):
"DELETE_DISABLED",
"REMOVE_LINKS_AND_DELETE_FILES",
"SELECTED",
package_ids=[gid],
package_ids=jd_downloads[gid]["ids"],
)
await task.listener.onDownloadComplete()
await retry_function(
jdownloader.device.downloads.remove_links,
package_ids=[gid],
package_ids=jd_downloads[gid]["ids"],
)
del jd_downloads[gid]
@ -41,15 +41,19 @@ async def _jd_listener():
)
except:
continue
finished = []
for pack in packages:
gid = pack["uuid"]
if (
gid in jd_downloads
and jd_downloads[gid] != "done"
and pack.get("finished", False)
):
jd_downloads[gid] = "done"
_onDownloadComplete(gid)
if pack.get("finished", False):
finished.append(pack["uuid"])
for gid in finished:
if gid in jd_downloads and jd_downloads[gid]["status"] != "done":
is_finished = True
for did in jd_downloads[gid]["ids"]:
if did not in finished:
is_finished = False
if is_finished:
jd_downloads[gid]["status"] = "done"
_onDownloadComplete(gid)
async def onDownloadStart():

View File

@ -42,7 +42,7 @@ async def configureDownload(_, query, obj):
class JDownloaderHelper:
def __init__(self, listener):
self._listener = listener
self._timeout = 180
self._timeout = 300
self._reply_to = ""
self.event = Event()
self.is_cancelled = False
@ -72,7 +72,7 @@ class JDownloaderHelper:
buttons.ibutton("Done Selecting", "jdq sdone")
buttons.ibutton("Cancel", "jdq cancel")
button = buttons.build_menu(2)
msg = f"Disable the unwanted files or change variants from myJdownloader site for <b>{self._listener.name}</b> but don't start it manually!\n\nAfter finish press Done Selecting!\nTimeout: 180s"
msg = f"Disable the unwanted files or change variants from myJdownloader site for <b>{self._listener.name}</b> but don't start it manually!\n\nAfter finish press Done Selecting!\nTimeout: 300s"
self._reply_to = await sendMessage(self._listener.message, msg, button)
await wrap_future(future)
if not self.is_cancelled:
@ -102,79 +102,85 @@ async def add_jd_download(listener, path):
[
{
"autoExtract": False,
"destinationFolder": path,
"links": listener.link,
"overwritePackagizerRules": True,
"packageName": listener.name or None,
}
],
)
while True:
if await retry_function(jdownloader.device.linkgrabber.is_collecting):
await sleep(0.5)
while await retry_function(jdownloader.device.linkgrabber.is_collecting):
pass
queued_downloads = await retry_function(
jdownloader.device.linkgrabber.query_packages,
[
{
"bytesTotal": True,
"saveTo": True,
"availableOnlineCount": True,
"availableTempUnknownCount": True,
"availableUnknownCount": True,
}
],
)
online_packages = []
size = 0
corrupted_packages = []
gid = 0
remove_unknown = False
name = ""
for pack in queued_downloads:
online = pack.get("onlineCount", 1)
if online == 0:
LOGGER.error(f"{pack.get('name', '')}. link: {listener.link}")
corrupted_packages.append(pack["uuid"])
continue
queued_downloads = await retry_function(
jdownloader.device.linkgrabber.query_packages,
[
{
"bytesTotal": True,
"saveTo": True,
"availableOnlineCount": True,
"availableTempUnknownCount": True,
"availableUnknownCount": True,
}
],
save_to = pack["saveTo"]
if gid == 0:
gid = pack["uuid"]
jd_downloads[gid] = {"status": "collect"}
name = save_to.replace("/root/Downloads/", "", 1).split("/", 1)[0]
if pack.get("tempUnknownCount", 0) > 0 or pack.get("unknownCount", 0) > 0:
remove_unknown = True
size += pack.get("bytesTotal", 0)
online_packages.append(pack["uuid"])
if save_to.startswith("/root/Downloads/"):
await retry_function(
jdownloader.device.linkgrabber.set_download_directory,
save_to.replace("/root/Downloads", path, 1),
[pack["uuid"]],
)
if not online_packages:
error = (
name or "Download Not Added! Maybe some issues in jdownloader or site!"
)
packages = []
online = 0
remove_unknown = False
for pack in queued_downloads:
save_to = pack["saveTo"]
if save_to.startswith(path):
if not packages:
if (
pack.get("tempUnknownCount", 0) > 0
or pack.get("unknownCount", 0) > 0
):
remove_unknown = True
name = pack["name"]
gid = pack["uuid"]
size = pack.get("bytesTotal", 0)
jd_downloads[gid] = "collect"
online += pack.get("onlineCount", 1)
if online == 0:
await listener.onDownloadError(name)
return
packages.append(pack["uuid"])
await listener.onDownloadError(error)
return
if len(packages) > 1:
await retry_function(
jdownloader.device.action,
"/linkgrabberv2/movetoNewPackage",
[[], packages, name, f"{path}/{name}"],
)
elif online > 1 and save_to == path:
await retry_function(
jdownloader.device.action,
"/linkgrabberv2/setDownloadDirectory",
[f"{path}/{name}", packages],
)
jd_downloads[gid]["ids"] = online_packages
if len(packages) == 1:
if remove_unknown:
links = await retry_function(
jdownloader.device.linkgrabber.query_links,
[{"packageUUIDs": packages, "availability": True}],
)
if to_remove := [
link["uuid"]
for link in links
if link["availability"].lower() != "online"
]:
await retry_function(
jdownloader.device.linkgrabber.remove_links, to_remove
)
break
corrupted_links = []
if remove_unknown:
links = await retry_function(
jdownloader.device.linkgrabber.query_links,
[{"packageUUIDs": online_packages, "availability": True}],
)
corrupted_links = [
link["uuid"]
for link in links
if link["availability"].lower() != "online"
]
if corrupted_packages or corrupted_links:
await retry_function(
jdownloader.device.linkgrabber.remove_links,
corrupted_links,
corrupted_packages,
)
listener.name = listener.name or name
@ -186,7 +192,7 @@ async def add_jd_download(listener, path):
if listener.select and await JDownloaderHelper(listener).waitForConfigurations():
await retry_function(
jdownloader.device.linkgrabber.remove_links,
package_ids=[gid],
package_ids=online_packages,
)
listener.removeFromSameDir()
return
@ -209,33 +215,34 @@ async def add_jd_download(listener, path):
await retry_function(
jdownloader.device.linkgrabber.move_to_downloadlist,
[],
[gid],
package_ids=online_packages,
)
await sleep(0.5)
download_packages = await retry_function(
jdownloader.device.downloads.query_packages,
[{"saveTo": True, "bytesTotal": True}],
[{"saveTo": True}],
)
exists = False
for pack in download_packages:
if pack["saveTo"].startswith(path):
async with jd_lock:
del jd_downloads[gid]
gid = pack["uuid"]
jd_downloads[gid] = "down"
exists = True
break
async with jd_lock:
packages = []
for pack in download_packages:
if pack["saveTo"].startswith(path):
if not packages:
del jd_downloads[gid]
gid = pack["uuid"]
jd_downloads[gid] = {"status": "down"}
packages.append(pack["uuid"])
if packages:
jd_downloads[gid]["ids"] = packages
if not exists:
if not packages:
await listener.onDownloadError("This Download have been removed manually!")
return
await retry_function(
jdownloader.device.downloads.force_download,
package_ids=[gid],
package_ids=packages,
)
async with task_dict_lock:

View File

@ -1,3 +1,5 @@
from time import time
from bot import LOGGER, jd_lock, jd_downloads
from bot.helper.ext_utils.jdownloader_booter import jdownloader
from bot.helper.ext_utils.bot_utils import retry_function
@ -8,22 +10,51 @@ from bot.helper.ext_utils.status_utils import (
)
def get_download(gid, old_info={}):
def _get_combined_info(result, start_time):
name = result[0].get("name")
hosts = result[0].get("hosts")
bytesLoaded = 0
bytesTotal = 0
for res in result:
st = res.get("status", "").lower()
if st and st != "finished":
status = st
bytesLoaded += res.get("bytesLoaded", 0)
bytesTotal += res.get("bytesTotal", 0)
try:
return jdownloader.device.downloads.query_packages(
speed = bytesLoaded / (time() - start_time)
eta = (bytesTotal - bytesLoaded) / speed
except:
speed = 0
eta = 0
return {
"name": name,
"status": status,
"speed": speed,
"eta": eta,
"hosts": hosts,
"bytesLoaded": bytesLoaded,
"bytesTotal": bytesTotal,
}
def get_download(gid, old_info, start_time):
try:
result = jdownloader.device.downloads.query_packages(
[
{
"bytesLoaded": True,
"bytesTotal": True,
"enabled": True,
"packageUUIDs": [gid],
"packageUUIDs": jd_downloads[gid]["ids"],
"speed": True,
"eta": True,
"status": True,
"hosts": True,
}
]
)[0]
)
return _get_combined_info(result, start_time) if len(result) > 1 else result[0]
except:
return old_info
@ -33,9 +64,10 @@ class JDownloaderStatus:
self.listener = listener
self._gid = gid
self._info = {}
self._start_time = time()
def _update(self):
self._info = get_download(int(self._gid), self._info)
self._info = get_download(int(self._gid), self._info, self._start_time)
def progress(self):
try:
@ -50,7 +82,7 @@ class JDownloaderStatus:
return f"{get_readable_file_size(self._info.get('speed', 0))}/s"
def name(self):
return self._info.get("name", self.listener.name)
return self._info.get("name") or self.listener.name
def size(self):
return get_readable_file_size(self._info.get("bytesTotal", 0))
@ -72,7 +104,8 @@ class JDownloaderStatus:
async def cancel_task(self):
LOGGER.info(f"Cancelling Download: {self.name()}")
await retry_function(
jdownloader.device.downloads.remove_links, package_ids=[int(self._gid)]
jdownloader.device.downloads.remove_links,
package_ids=jd_downloads[int(self._gid)]["ids"],
)
async with jd_lock:
del jd_downloads[int(self._gid)]

View File

@ -3,7 +3,7 @@ from pyrogram.filters import command
from base64 import b64encode
from re import match as re_match
from aiofiles.os import path as aiopath
from myjdapi.exception import MYJDException
from myjd.exception import MYJDException
from bot.helper.ext_utils.exceptions import DirectDownloadLinkException
from bot.helper.mirror_utils.download_utils.direct_downloader import add_direct_download

37
myjd/__init__.py Normal file
View File

@ -0,0 +1,37 @@
from .myjdapi import Myjdapi
from .exception import (
MYJDException,
MYJDConnectionException,
MYJDDeviceNotFoundException,
MYJDDecodeException,
MYJDApiException,
MYJDApiCommandNotFoundException,
MYJDApiInterfaceNotFoundException,
MYJDAuthFailedException,
MYJDBadParametersException,
MYJDBadRequestException,
MYJDChallengeFailedException,
MYJDEmailForbiddenException,
MYJDEmailInvalidException,
MYJDErrorEmailNotConfirmedException,
MYJDFailedException,
MYJDFileNotFoundException,
MYJDInternalServerErrorException,
MYJDMaintenanceException,
MYJDMethodForbiddenException,
MYJDOfflineException,
MYJDOutdatedException,
MYJDOverloadException,
MYJDSessionException,
MYJDStorageAlreadyExistsException,
MYJDStorageInvalidKeyException,
MYJDStorageInvalidStorageIdException,
MYJDStorageKeyNotFoundException,
MYJDStorageLimitReachedException,
MYJDStorageNotFoundException,
MYJDTokenInvalidException,
MYJDTooManyRequestsException,
MYJDUnknownException,
)
__version__ = "1.1.7"

36
myjd/const.py Normal file
View File

@ -0,0 +1,36 @@
"""Constants of the MyJDownloader API."""
# API Documentation: https://my.jdownloader.org/developers
# MyJdownloader exception source
EXCEPTION_MYJD = "MYJD"
EXCEPTION_DEVICE = "DEVICE"
# MyJdownloader exception type
EXCEPTION_API_COMMAND_NOT_FOUND = "API_COMMAND_NOT_FOUND"
EXCEPTION_API_INTERFACE_NOT_FOUND = "API_INTERFACE_NOT_FOUND"
EXCEPTION_AUTH_FAILED = "AUTH_FAILED"
EXCEPTION_BAD_PARAMETERS = "BAD_PARAMETERS"
EXCEPTION_BAD_REQUEST = "BAD_REQUEST"
EXCEPTION_CHALLENGE_FAILED = "CHALLENGE_FAILED"
EXCEPTION_EMAIL_FORBIDDEN = "EMAIL_FORBIDDEN"
EXCEPTION_EMAIL_INVALID = "EMAIL_INVALID"
EXCEPTION_ERROR_EMAIL_NOT_CONFIRMED = "ERROR_EMAIL_NOT_CONFIRMED"
EXCEPTION_FAILED = "FAILED"
EXCEPTION_FILE_NOT_FOUND = "FILE_NOT_FOUND"
EXCEPTION_INTERNAL_SERVER_ERROR = "INTERNAL_SERVER_ERROR"
EXCEPTION_MAINTENANCE = "MAINTENANCE"
EXCEPTION_METHOD_FORBIDDEN = "METHOD_FORBIDDEN"
EXCEPTION_OFFLINE = "OFFLINE"
EXCEPTION_OUTDATED = "OUTDATED"
EXCEPTION_OVERLOAD = "OVERLOAD"
EXCEPTION_SESSION = "SESSION"
EXCEPTION_STORAGE_ALREADY_EXISTS = "STORAGE_ALREADY_EXISTS"
EXCEPTION_STORAGE_INVALID_KEY = "STORAGE_INVALID_KEY"
EXCEPTION_STORAGE_INVALID_STORAGEID = "STORAGE_INVALID_STORAGEID"
EXCEPTION_STORAGE_KEY_NOT_FOUND = "STORAGE_KEY_NOT_FOUND"
EXCEPTION_STORAGE_LIMIT_REACHED = "STORAGE_LIMIT_REACHED"
EXCEPTION_STORAGE_NOT_FOUND = "STORAGE_NOT_FOUND"
EXCEPTION_TOKEN_INVALID = "TOKEN_INVALID"
EXCEPTION_TOO_MANY_REQUESTS = "TOO_MANY_REQUESTS"
EXCEPTION_UNKNOWN = "UNKNOWN"

266
myjd/exception.py Normal file
View File

@ -0,0 +1,266 @@
"""Exceptions of the MyJDownloader API."""
from .const import (
EXCEPTION_API_COMMAND_NOT_FOUND,
EXCEPTION_API_INTERFACE_NOT_FOUND,
EXCEPTION_AUTH_FAILED,
EXCEPTION_BAD_PARAMETERS,
EXCEPTION_BAD_REQUEST,
EXCEPTION_CHALLENGE_FAILED,
EXCEPTION_EMAIL_FORBIDDEN,
EXCEPTION_EMAIL_INVALID,
EXCEPTION_ERROR_EMAIL_NOT_CONFIRMED,
EXCEPTION_FAILED,
EXCEPTION_FILE_NOT_FOUND,
EXCEPTION_INTERNAL_SERVER_ERROR,
EXCEPTION_MAINTENANCE,
EXCEPTION_METHOD_FORBIDDEN,
EXCEPTION_OFFLINE,
EXCEPTION_OUTDATED,
EXCEPTION_OVERLOAD,
EXCEPTION_SESSION,
EXCEPTION_STORAGE_ALREADY_EXISTS,
EXCEPTION_STORAGE_INVALID_KEY,
EXCEPTION_STORAGE_INVALID_STORAGEID,
EXCEPTION_STORAGE_KEY_NOT_FOUND,
EXCEPTION_STORAGE_LIMIT_REACHED,
EXCEPTION_STORAGE_NOT_FOUND,
EXCEPTION_TOKEN_INVALID,
EXCEPTION_TOO_MANY_REQUESTS,
EXCEPTION_UNKNOWN,
)
class MYJDException(BaseException):
"""Base MyJDownloader Exception."""
pass
class MYJDConnectionException(MYJDException):
"""Connection Exception."""
pass
class MYJDDeviceNotFoundException(MYJDException):
"""Device not found Exception."""
pass
class MYJDDecodeException(MYJDException):
"""Decode Exception."""
pass
class MYJDApiException(MYJDException):
"""Base MyJDownloader API Exception."""
@classmethod
def get_exception(
cls, exception_source, exception_type=EXCEPTION_UNKNOWN, *args, **kwargs
):
"""Get exception object from MyJDownloader exception type."""
return EXCEPTION_CLASSES.get(exception_type.upper(), MYJDUnknownException)(
exception_source, *args, **kwargs
)
def __init__(self, exception_source, *args, **kwargs):
"""Initialize MyJDownloader API exception."""
self.source = exception_source.upper()
super(MYJDApiException, self).__init__(*args, **kwargs)
class MYJDApiCommandNotFoundException(MYJDApiException):
"""MyJDownloader command not found API Exception."""
pass
class MYJDApiInterfaceNotFoundException(MYJDApiException):
"""MyJDownloader interface not found API Exception."""
pass
class MYJDAuthFailedException(MYJDApiException):
"""MyJDownloader auth failed API Exception."""
pass
class MYJDBadParametersException(MYJDApiException):
"""MyJDownloader bad parameters API Exception."""
pass
class MYJDBadRequestException(MYJDApiException):
"""MyJDownloader bad request API Exception."""
pass
class MYJDChallengeFailedException(MYJDApiException):
"""MyJDownloader challenge failed API Exception."""
pass
class MYJDEmailForbiddenException(MYJDApiException):
"""MyJDownloader email forbidden API Exception."""
pass
class MYJDEmailInvalidException(MYJDApiException):
"""MyJDownloader email invalid API Exception."""
pass
class MYJDErrorEmailNotConfirmedException(MYJDApiException):
"""MyJDownloader email not confirmed API Exception."""
pass
class MYJDFailedException(MYJDApiException):
"""MyJDownloader failed API Exception."""
pass
class MYJDFileNotFoundException(MYJDApiException):
"""MyJDownloader file not found API Exception."""
pass
class MYJDInternalServerErrorException(MYJDApiException):
"""MyJDownloader internal server error API Exception."""
pass
class MYJDMaintenanceException(MYJDApiException):
"""MyJDownloader maintenance API Exception."""
pass
class MYJDMethodForbiddenException(MYJDApiException):
"""MyJDownloader method forbidden API Exception."""
pass
class MYJDOfflineException(MYJDApiException):
"""MyJDownloader offline API Exception."""
pass
class MYJDOutdatedException(MYJDApiException):
"""MyJDownloader outdated API Exception."""
pass
class MYJDOverloadException(MYJDApiException):
"""MyJDownloader overload API Exception."""
pass
class MYJDSessionException(MYJDApiException):
"""MyJDownloader session API Exception."""
pass
class MYJDStorageAlreadyExistsException(MYJDApiException):
"""MyJDownloader storage already exists API Exception."""
pass
class MYJDStorageInvalidKeyException(MYJDApiException):
"""MyJDownloader storage invalid key API Exception."""
pass
class MYJDStorageInvalidStorageIdException(MYJDApiException):
"""MyJDownloader storage invalid storage id API Exception."""
pass
class MYJDStorageKeyNotFoundException(MYJDApiException):
"""MyJDownloader storage key not found API Exception."""
pass
class MYJDStorageLimitReachedException(MYJDApiException):
"""MyJDownloader storage limit reached API Exception."""
pass
class MYJDStorageNotFoundException(MYJDApiException):
"""MyJDownloader storage not found API Exception."""
pass
class MYJDTokenInvalidException(MYJDApiException):
"""MyJDownloader token invalid API Exception."""
pass
class MYJDTooManyRequestsException(MYJDApiException):
"""MyJDownloader too many request API Exception."""
pass
class MYJDUnknownException(MYJDApiException):
"""MyJDownloader unknown API Exception."""
pass
EXCEPTION_CLASSES = {
EXCEPTION_API_COMMAND_NOT_FOUND: MYJDApiCommandNotFoundException,
EXCEPTION_API_INTERFACE_NOT_FOUND: MYJDApiInterfaceNotFoundException,
EXCEPTION_AUTH_FAILED: MYJDAuthFailedException,
EXCEPTION_BAD_PARAMETERS: MYJDBadParametersException,
EXCEPTION_BAD_REQUEST: MYJDBadRequestException,
EXCEPTION_CHALLENGE_FAILED: MYJDChallengeFailedException,
EXCEPTION_EMAIL_FORBIDDEN: MYJDEmailForbiddenException,
EXCEPTION_EMAIL_INVALID: MYJDEmailInvalidException,
EXCEPTION_ERROR_EMAIL_NOT_CONFIRMED: MYJDErrorEmailNotConfirmedException,
EXCEPTION_FAILED: MYJDFailedException,
EXCEPTION_FILE_NOT_FOUND: MYJDFileNotFoundException,
EXCEPTION_INTERNAL_SERVER_ERROR: MYJDInternalServerErrorException,
EXCEPTION_MAINTENANCE: MYJDMaintenanceException,
EXCEPTION_METHOD_FORBIDDEN: MYJDMethodForbiddenException,
EXCEPTION_OFFLINE: MYJDOfflineException,
EXCEPTION_OUTDATED: MYJDOutdatedException,
EXCEPTION_OVERLOAD: MYJDOverloadException,
EXCEPTION_SESSION: MYJDSessionException,
EXCEPTION_STORAGE_ALREADY_EXISTS: MYJDStorageAlreadyExistsException,
EXCEPTION_STORAGE_INVALID_KEY: MYJDStorageInvalidKeyException,
EXCEPTION_STORAGE_INVALID_STORAGEID: MYJDStorageInvalidStorageIdException,
EXCEPTION_STORAGE_KEY_NOT_FOUND: MYJDStorageKeyNotFoundException,
EXCEPTION_STORAGE_LIMIT_REACHED: MYJDStorageLimitReachedException,
EXCEPTION_STORAGE_NOT_FOUND: MYJDStorageNotFoundException,
EXCEPTION_TOKEN_INVALID: MYJDTokenInvalidException,
EXCEPTION_TOO_MANY_REQUESTS: MYJDTooManyRequestsException,
EXCEPTION_UNKNOWN: MYJDUnknownException,
}

1246
myjd/myjdapi.py Normal file

File diff suppressed because it is too large Load Diff

View File

@ -17,10 +17,10 @@ gunicorn
httpx
lxml
motor
myjdapi
natsort
pillow
psutil
pycryptodome
pymongo
pyrogram
python-dotenv