Update app.py
Browse files
app.py
CHANGED
@@ -481,6 +481,75 @@ async def download_hls_video(request: Request):
|
|
481 |
return {"url": download_url}
|
482 |
|
483 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
484 |
@app.post("/multi")
|
485 |
async def multi_download(request: Request):
|
486 |
user_ip = get_user_ip(request)
|
@@ -529,14 +598,21 @@ async def multi_download(request: Request):
|
|
529 |
is_youtube_url = re.search(r'(youtube\.com|youtu\.be)', video_url) is not None
|
530 |
|
531 |
if is_youtube_url:
|
532 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
533 |
dl_url = f'https://chrunos-grab.hf.space/yt/dl?url={encoded_url}&{parameter}'
|
534 |
if dl_url and "http" in dl_url:
|
535 |
return {"url": dl_url, "requests_remaining": rate_limiter.max_requests - rate_limiter.get_current_count(user_ip)}
|
536 |
else:
|
537 |
return {
|
538 |
"error": "Failed to Fetch the video."
|
539 |
-
}
|
540 |
|
541 |
else:
|
542 |
dl_url = await get_track_download_url(video_url, quality)
|
|
|
481 |
return {"url": download_url}
|
482 |
|
483 |
|
484 |
+
def get_youtube_download_url_from_apis(video_url: str) -> str:
|
485 |
+
encoded_url = urllib.parse.quote(str(video_url), safe='')
|
486 |
+
|
487 |
+
api_configs = [
|
488 |
+
{
|
489 |
+
"name": "API 1",
|
490 |
+
"url": f"https://velynapi.vercel.app/api/downloader/ytmp4?url={encoded_url}",
|
491 |
+
"headers": {"accept": "*/*"},
|
492 |
+
"parser": lambda data: data.get("data", {}).get("url")
|
493 |
+
if data.get("status") and data.get("data", {}).get("status")
|
494 |
+
else None
|
495 |
+
},
|
496 |
+
{
|
497 |
+
"name": "API 2",
|
498 |
+
"url": f"https://velynapi.vercel.app/api/downloader/ytmp4v2?url={encoded_url}",
|
499 |
+
"headers": {"accept": "application/json"},
|
500 |
+
"parser": lambda data: data.get("data", {}).get("advancedInfo", {}).get("videoMp4")
|
501 |
+
if data.get("status")
|
502 |
+
else None
|
503 |
+
}
|
504 |
+
]
|
505 |
+
|
506 |
+
for api in api_configs:
|
507 |
+
logger.info(f"Attempting to fetch download URL using {api['name']} ({api['url']})...")
|
508 |
+
try:
|
509 |
+
response = requests.get(api["url"], headers=api["headers"], timeout=20) # 15-second timeout
|
510 |
+
|
511 |
+
# Raise an exception for HTTP errors (e.g., 404, 500)
|
512 |
+
response.raise_for_status()
|
513 |
+
|
514 |
+
# Attempt to parse the response as JSON
|
515 |
+
# response.json() will raise requests.exceptions.JSONDecodeError if not valid JSON
|
516 |
+
data = response.json()
|
517 |
+
|
518 |
+
# Use the custom parser to extract the download URL
|
519 |
+
download_url = api["parser"](data)
|
520 |
+
|
521 |
+
if download_url:
|
522 |
+
logger.info(f"Successfully retrieved download URL from {api['name']}: {download_url}")
|
523 |
+
return download_url
|
524 |
+
else:
|
525 |
+
# This means the request was successful (HTTP 200) and JSON was valid,
|
526 |
+
# but the expected keys/values for the URL were not found or statuses were false.
|
527 |
+
logger.info(f"{api['name']} responded successfully, but a valid download URL was not found in the expected structure or conditions were not met.")
|
528 |
+
# Detailed logging for why parsing might have failed to find the URL:
|
529 |
+
if not data.get("status"):
|
530 |
+
logger.info(f" Reason: Root 'status' was false or missing in {api['name']}'s response.")
|
531 |
+
elif api['name'] == "API 1" and (not data.get("data") or not data.get("data", {}).get("status")):
|
532 |
+
logger.info(f" Reason: 'data' field was missing, or 'data.status' was false or missing in {api['name']}'s response.")
|
533 |
+
|
534 |
+
except requests.exceptions.HTTPError as e:
|
535 |
+
logger.info(f"HTTP error occurred while calling {api['name']}: {e}")
|
536 |
+
except requests.exceptions.Timeout:
|
537 |
+
logger.info(f"Request to {api['name']} timed out.")
|
538 |
+
except requests.exceptions.ConnectionError as e:
|
539 |
+
logger.info(f"Could not connect to {api['name']}: {e}")
|
540 |
+
except requests.exceptions.JSONDecodeError:
|
541 |
+
# This catches errors if response.json() fails
|
542 |
+
logger.info(f"Failed to decode JSON response from {api['name']}. Response text (first 200 chars): {response.text[:200] if response else 'No response text'}")
|
543 |
+
except requests.exceptions.RequestException as e: # Catch any other request-related error
|
544 |
+
logger.info(f"An error occurred during the request to {api['name']}: {e}")
|
545 |
+
except Exception as e: # Catch-all for other unexpected errors (e.g., in parser logic if data is malformed)
|
546 |
+
logger.info(f"An unexpected error occurred while processing the response from {api['name']}: {e}")
|
547 |
+
|
548 |
+
logger.info(f"Failed to get URL from {api['name']}. Trying next API if available.")
|
549 |
+
|
550 |
+
logger.info("Both APIs failed to retrieve a download URL.")
|
551 |
+
return None
|
552 |
+
|
553 |
@app.post("/multi")
|
554 |
async def multi_download(request: Request):
|
555 |
user_ip = get_user_ip(request)
|
|
|
598 |
is_youtube_url = re.search(r'(youtube\.com|youtu\.be)', video_url) is not None
|
599 |
|
600 |
if is_youtube_url:
|
601 |
+
dl_url = get_youtube_download_url_from_apis(video_url)
|
602 |
+
if dl_url:
|
603 |
+
return {"url": dl_url, "requests_remaining": rate_limiter.max_requests - rate_limiter.get_current_count(user_ip)}
|
604 |
+
else:
|
605 |
+
return {
|
606 |
+
"error": "Failed to Fetch the video."
|
607 |
+
}
|
608 |
+
'''encoded_url = urllib.parse.quote(str(video_url), safe='')
|
609 |
dl_url = f'https://chrunos-grab.hf.space/yt/dl?url={encoded_url}&{parameter}'
|
610 |
if dl_url and "http" in dl_url:
|
611 |
return {"url": dl_url, "requests_remaining": rate_limiter.max_requests - rate_limiter.get_current_count(user_ip)}
|
612 |
else:
|
613 |
return {
|
614 |
"error": "Failed to Fetch the video."
|
615 |
+
} '''
|
616 |
|
617 |
else:
|
618 |
dl_url = await get_track_download_url(video_url, quality)
|