Chrunos commited on
Commit
673b9fd
·
verified ·
1 Parent(s): 59c77bf

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +189 -390
app.py CHANGED
@@ -29,12 +29,13 @@ from typing import Dict, Any
29
  import re
30
  import asyncio
31
  import cloudscraper
32
- import httpx
33
- from bs4 import BeautifulSoup
34
- from pydantic import BaseModel
35
 
36
  tmp_dir = tempfile.gettempdir()
37
- BASE_URL = "https://chrunos-zam.hf.space"
 
 
 
38
 
39
 
40
  def env_to_cookies(env_content: str, output_file: str) -> None:
@@ -126,119 +127,10 @@ async def get_video_url(youtube_url: str):
126
 
127
 
128
 
129
-
130
- @app.get("/script")
131
- async def get_transcript(youtube_url: str, language: str = None):
132
- try:
133
- # Set up yt-dlp options
134
- ydl_opts = {
135
- 'skip_download': True,
136
- 'writesubtitles': True,
137
- 'writeautomaticsub': True,
138
- 'outtmpl': '%(id)s.%(ext)s',
139
- 'noplaylist': True,
140
- 'cookiefile': "firefox-cookies.txt"
141
- }
142
-
143
- # If a language is specified, only download that language
144
- # Otherwise, we'll first get video info to determine the original language
145
- if language:
146
- ydl_opts['subtitleslangs'] = [language]
147
-
148
- env_to_cookies_from_env("firefox-cookies.txt")
149
- logger.info(f"Current directory files (before): {os.listdir('.')}")
150
-
151
- # First, get video info without downloading anything
152
- with yt_dlp.YoutubeDL({**ydl_opts, 'skip_download': True, 'writesubtitles': False, 'writeautomaticsub': False}) as ydl:
153
- info = ydl.extract_info(youtube_url, download=False)
154
- video_id = info['id']
155
- logger.info(f"Video ID: {video_id}")
156
-
157
- # If no language specified, try to use the original language
158
- if not language:
159
- # Try to determine the original language if available in the info
160
- if 'subtitles' in info and info['subtitles']:
161
- # Use the first available subtitle language
162
- available_languages = list(info['subtitles'].keys())
163
- if available_languages:
164
- language = available_languages[0]
165
- logger.info(f"Using detected language: {language}")
166
- ydl_opts['subtitleslangs'] = [language]
167
- else:
168
- # Fall back to 'en' if can't determine
169
- language = 'en'
170
- ydl_opts['subtitleslangs'] = [language]
171
-
172
- # Now download the subtitle in the selected language
173
- with yt_dlp.YoutubeDL(ydl_opts) as ydl:
174
- ydl.extract_info(youtube_url, download=True)
175
-
176
- # Check actual downloaded files
177
- logger.info(f"Current directory files (after extraction): {os.listdir('.')}")
178
-
179
- # Look for the subtitle file with the specified language
180
- subtitle_files = [f for f in os.listdir('.')
181
- if f.startswith(video_id) and any(ext in f for ext in ['.vtt', '.srt', '.ttml', '.json3'])]
182
-
183
- # If specific language requested, filter for that language
184
- if language:
185
- lang_subtitle_files = [f for f in subtitle_files if language in f]
186
- if lang_subtitle_files:
187
- subtitle_files = lang_subtitle_files
188
-
189
- logger.info(f"Potential subtitle files: {subtitle_files}")
190
-
191
- if subtitle_files:
192
- # Process the first found subtitle file
193
- subtitle_file = subtitle_files[0]
194
- logger.info(f"Processing subtitle file: {subtitle_file}")
195
-
196
- with open(subtitle_file, 'r', encoding='utf-8') as f:
197
- content = f.read()
198
-
199
- # Add format-specific parsing
200
- if subtitle_file.endswith('.json3'):
201
- import json
202
- subs = json.loads(content)
203
- text = ' '.join([e['segs'][0]['utf8'] for e in subs['events'] if e.get('segs')])
204
- elif subtitle_file.endswith('.vtt'):
205
- text = ' '.join(line.strip() for line in content.split('\n')
206
- if not line.startswith('WEBVTT')
207
- and '-->' not in line
208
- and not line.strip().isdigit()
209
- and line.strip())
210
- elif subtitle_file.endswith('.srt'):
211
- # Simple SRT parsing - skip timestamps and numbers
212
- lines = []
213
- for line in content.split('\n'):
214
- if not line.strip().isdigit() and '-->' not in line and line.strip():
215
- lines.append(line.strip())
216
- text = ' '.join(lines)
217
- else:
218
- text = f"Unsupported format: {subtitle_file}"
219
-
220
- # Clean up files to avoid cluttering the directory
221
- for f in subtitle_files:
222
- try:
223
- os.remove(f)
224
- except:
225
- logger.warning(f"Could not remove file: {f}")
226
-
227
- detected_language = subtitle_file.split('.')[-2] if '.' in subtitle_file else "unknown"
228
- return {"transcript": text, "language": detected_language}
229
-
230
- return {"transcript": f"No subtitle files found for {video_id}", "language": "none"}
231
- except Exception as e:
232
- logger.error(f"Error: {str(e)}", exc_info=True)
233
- raise HTTPException(status_code=500, detail=str(e))
234
-
235
-
236
-
237
  # Define a global temporary download directory
238
  global_download_dir = tempfile.mkdtemp()
239
 
240
-
241
-
242
  class RateLimiter:
243
  def __init__(self, max_requests: int, time_window: timedelta):
244
  self.max_requests = max_requests
@@ -275,7 +167,7 @@ class RateLimiter:
275
 
276
  # Initialize rate limiter with 100 requests per day
277
  rate_limiter = RateLimiter(
278
- max_requests=20,
279
  time_window=timedelta(days=1)
280
  )
281
 
@@ -308,16 +200,18 @@ class ApiRotator:
308
 
309
  # In your function:
310
  api_rotator = ApiRotator([
311
- "https://dwnld.nichind.dev",
312
- "https://cobalt-api.kwiatekmiki.com",
313
- "https://yt.edd1e.xyz/",
 
314
  "https://cobalt-api.ayo.tf",
315
- "https://cblt.fariz.dev"
 
316
  ])
317
 
318
 
319
 
320
- async def get_track_download_url(video_url: str) -> str:
321
  apis = api_rotator.get_prioritized_apis()
322
  session = cloudscraper.create_scraper() # Requires cloudscraper package
323
  headers = {
@@ -325,6 +219,11 @@ async def get_track_download_url(video_url: str) -> str:
325
  "Content-Type": "application/json",
326
  "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36"
327
  }
 
 
 
 
 
328
 
329
  for i, api_url in enumerate(apis):
330
  try:
@@ -333,7 +232,7 @@ async def get_track_download_url(video_url: str) -> str:
333
  response = session.post(
334
  api_url,
335
  timeout=20,
336
- json={"url": y_url, "videoQuality": "720", "filenameStyle": "pretty"},
337
  headers=headers
338
  )
339
  logger.info(f"Response status: {response.status_code}")
@@ -343,7 +242,7 @@ async def get_track_download_url(video_url: str) -> str:
343
  json_response = response.json()
344
  error_code = json_response.get("error", {}).get("code", "")
345
 
346
- if error_code == "error.api.content.video.unavailable":
347
  logger.warning(f"Video unavailable error from {api_url}")
348
  break # Only break for specific error
349
 
@@ -359,192 +258,168 @@ async def get_track_download_url(video_url: str) -> str:
359
  return {"error": "Download URL not found"}
360
 
361
 
362
- def jio_search(query: str, quality: str) -> str:
363
- try:
364
- # Construct the API URL
365
- api_url = f"https://saavn.dev/api/search/songs?query={query}"
366
- session = cloudscraper.create_scraper()
367
- # Make the API request
368
- response = session.get(api_url)
369
- # Check if the request was successful
370
- response.raise_for_status()
371
- # Get the data from the response
372
- data = response.json().get("data")
373
- if not data:
374
- logger.error("No data found in the response.")
375
- raise HTTPException(status_code=404, detail="No data found for the given query.")
376
- # Get the song results
377
- song_results = data.get("results")
378
- if not song_results or len(song_results) == 0:
379
- logger.error("No song results found in the response.")
380
- raise HTTPException(status_code=404, detail="No song results found for the given query.")
381
- # Iterate through each song result
382
- for song in song_results:
383
- download_urls = song.get("downloadUrl")
384
- if download_urls:
385
- for download_url in download_urls:
386
- if download_url.get("quality") == quality:
387
- return download_url.get("url")
388
- logger.error(f"No download URL found for quality {quality} in the search results for query {query}.")
389
- raise HTTPException(status_code=404, detail=f"No download URL found for quality {quality} in the search results for query {query}.")
390
- except cloudscraper.exceptions.CloudflareChallengeError as cf_err:
391
- logger.error(f"Cloudflare challenge error while searching for {query}: {cf_err}")
392
- raise HTTPException(status_code=503, detail="Cloudflare challenge failed")
393
- except HTTPException:
394
- # Re - raise the HTTPException if it's already raised
395
- raise
396
- except Exception as e:
397
- logger.error(f"Error while searching for {query}: {e}")
398
- raise HTTPException(status_code=500, detail=f"An error occurred while searching: {str(e)}")
399
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
400
 
401
- def jio_fetch(url: str, quality: str) -> str:
402
- try:
403
- # Construct the API URL
404
- api_url = f"https://saavn.dev/api/songs?link={url}"
405
- session = cloudscraper.create_scraper()
406
- # Make the API request
407
- response = session.get(api_url)
408
- # Check if the request was successful
409
- response.raise_for_status()
410
- data = response.json()
411
- song_data = data.get("data")
412
- if not song_data or len(song_data) == 0:
413
- logger.error("No data found in the response.")
414
- raise HTTPException(status_code=404, detail="No data found for the given URL.")
415
- download_urls = song_data[0].get("downloadUrl")
416
- if not download_urls:
417
- logger.error("No download URLs found in the response.")
418
- raise HTTPException(status_code=404, detail="No download URLs found for the given song.")
419
- for download_url in download_urls:
420
- if download_url.get("quality") == quality:
421
- return download_url.get("url")
422
- logger.error(f"No download URL found for quality {quality}.")
423
- raise HTTPException(status_code=404, detail=f"No download URL found for quality {quality}.")
424
- except cloudscraper.exceptions.CloudflareChallengeError as cf_err:
425
- logger.error(f"Cloudflare challenge error while fetching {url}: {cf_err}")
426
- raise HTTPException(status_code=503, detail="Cloudflare challenge failed")
427
- except HTTPException:
428
- # Re - raise the HTTPException if it's already raised
429
- raise
430
- except Exception as e:
431
- logger.error(f"Error while fetching {url}: {e}")
432
- raise HTTPException(status_code=500, detail=f"An error occurred while fetching: {str(e)}")
433
-
434
- # Define the request model
435
- class JioDownloadRequest(BaseModel):
436
- url: str = None
437
- query: str = None
438
- quality: str = None
439
 
440
- @app.post("/jio_dl")
441
- async def jio_download(request: JioDownloadRequest):
442
- try:
443
- url = request.url
444
- query = request.query
445
- quality = request.quality
446
- if url and quality:
447
- logger.info(f'input url: {url}')
448
- download_url = jio_fetch(url, quality)
449
- return {"download_url": download_url}
450
- elif query:
451
- logger.info(f'input query: {query}')
452
- download_url = jio_search(query, quality)
453
- return {"download_url": download_url}
454
- else:
455
- logger.error("Missing 'url' and 'quality' or 'query' in request data.")
456
- raise HTTPException(status_code=400, detail="Missing 'url' and 'quality' or 'query' in request data")
457
- except HTTPException:
458
- # Re - raise the HTTPException if it's already raised
459
- raise
460
- except Exception as e:
461
- logger.error(f"Error in jio_download: {e}")
462
- raise HTTPException(status_code=500, detail=f"An error occurred during the operation: {str(e)}")
463
 
 
 
464
 
465
- @app.post("/jio_dls")
466
- async def jio_download(request: JioDownloadRequest):
467
- try:
468
- url = request.url
469
- quality = request.quality
470
- query = request.query
471
- if quality == '320kbps':
472
- return {
473
- "error": "Quality 320kbps is for Premium users only",
474
- "premium": "https://chrunos.com/premium-shortcuts/"
475
- }
476
- if url and quality:
477
- logger.info(f'input url: {url}')
478
- download_url = jio_fetch(url, quality)
479
- return {"download_url": download_url}
480
- elif query:
481
- logger.info(f'input query: {query}')
482
- download_url = jio_search(query, quality)
483
- return {"download_url": download_url}
484
- else:
485
- logger.error("Missing 'url' and 'quality' or 'query' in request data.")
486
- raise HTTPException(status_code=400, detail="Missing 'url' and 'quality' or 'query' in request data")
487
- except HTTPException:
488
- # Re - raise the HTTPException if it's already raised
489
- raise
490
- except Exception as e:
491
- logger.error(f"Error in jio_download: {e}")
492
- raise HTTPException(status_code=500, detail=f"An error occurred during the operation: {str(e)}")
493
-
494
 
 
 
495
 
 
 
496
 
 
 
 
 
 
 
 
497
 
 
 
498
 
 
 
 
 
 
 
 
 
499
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
500
 
501
 
502
- EXTRACT_API = os.getenv("EXTRACT_API")
503
  ALT_API = os.getenv("ALT_API")
504
 
505
-
506
  def extract_video_info(video_url: str) -> str:
507
- api_urls = [f'{ALT_API}?url={video_url}', f'{EXTRACT_API}?url={video_url}']
508
- for api_url in api_urls:
509
- logger.info(api_url)
510
- session = cloudscraper.create_scraper()
511
- try:
512
- response = session.get(api_url, timeout=20)
513
-
514
- if response.status_code == 200:
515
- json_response = response.json()
516
- result = []
517
- if 'formats' in json_response:
518
- for format_item in json_response['formats']:
519
- format_url = format_item.get('url')
520
- format_id = format_item.get('format_id')
521
- p_cookies = format_item.get('cookies')
522
- if format_id and format_url:
523
- result.append({
524
- "url": format_url,
525
- "format_id": format_id,
526
- "cookies": p_cookies
527
- })
528
- title = json_response.get('title')
529
- logger.info(title)
530
- if "pornhub.com" in video_url:
531
- p_result = [item for item in result if 'hls' in item['format_id']]
532
- return p_result
533
- else:
534
- if len(result) == 1:
535
- new_item = {
536
- "format_id": "This is Fake, Don't Choose This One",
537
- "url": "none"
538
- }
539
- result.append(new_item)
540
- return result
 
 
 
541
  else:
542
- return {"error": "No formats available"}
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
543
  else:
544
- logger.warning(f"Request failed with status code {response.status_code}, API: {api_url}")
545
- except Exception as e:
546
- logger.error(f"An error occurred: {e}")
547
- return {"error": "Both APIs failed to provide valid results."}
 
 
 
 
 
 
 
 
 
 
 
 
 
 
548
 
549
 
550
  @app.post("/test")
@@ -571,6 +446,7 @@ async def download_hls_video(request: Request):
571
  'noprogress': True,
572
  'merge_output_format': 'mp4'
573
  }
 
574
  try:
575
  await run_in_threadpool(lambda: yt_dlp.YoutubeDL(ydl_opts).download([hls_url]))
576
  except Exception as e:
@@ -589,61 +465,34 @@ async def download_hls_video(request: Request):
589
 
590
 
591
 
592
- async def get_audio_download_url(track_id: str, quality: str) -> str:
593
- if quality == 'mp3':
594
- type = 'audio'
595
- quality = 128
596
- else:
597
- type = 'video'
598
- donwnload_url = f'https://chrunos-shadl.hf.space/yt/dl?url={track_id}&type={type}&quality={quality}'
599
- return donwnload_url
600
-
601
 
602
- @app.post("/maxs")
603
  async def download_high_quality_video(request: Request):
604
- user_ip = get_user_ip(request)
605
-
606
- if rate_limiter.is_rate_limited(user_ip):
607
- current_count = rate_limiter.get_current_count(user_ip)
608
- raise HTTPException(
609
- status_code=429,
610
- detail={
611
- "error": "You have exceeded the maximum number of requests per day. Please try again tomorrow.",
612
- "url": "https://t.me/chrunoss"
613
- }
614
- )
615
-
616
-
617
  data = await request.json()
618
- restricted_domain = "chrunos.com"
619
  video_url = data.get('url')
620
- quality = data.get('quality', '720') # Default to 1080p if not specified
621
- logger.info(f'input url: {video_url}, {quality}')
622
- is_youtube_url = re.search(r'(youtube\.com|youtu\.be|instagram\.com)', video_url) is not None
623
- if video_url and restricted_domain in video_url:
624
- return {"error": "What is wrong with you?", "url": "https://t.me/chrunoss"}
625
-
626
  # Check if the requested quality is above 1080p
627
- if int(quality) > 720:
628
- error_message = "Quality above 720p is for Premium Members Only. Please check the URL for more information."
629
- help_url = "https://chrunos.com/premium-shortcuts/" # Replace with your actual URL
630
- return {"error": error_message, "url": help_url}
631
 
632
  cookiefile = "firefox-cookies.txt"
633
  env_to_cookies_from_env("firefox-cookies.txt")
634
 
635
  timestamp = datetime.now().strftime('%Y%m%d%H%M%S')
636
- output_template = str(Path(global_download_dir) / f'%(title).70s_{timestamp}.%(ext)s')
637
 
638
  # Convert quality string to height
639
  height_map = {
640
- '240': 240,
641
- '360': 360,
642
  '480': 480,
643
  '720': 720,
644
- '1080': 1080
 
 
645
  }
646
- max_height = height_map.get(quality, 720) # Use the quality variable correctly
647
 
648
  # Determine format string based on quality
649
  format_str = f'bestvideo[height<={max_height}][vcodec^=avc]+bestaudio/best'
@@ -654,22 +503,12 @@ async def download_high_quality_video(request: Request):
654
  'quiet': True,
655
  'no_warnings': True,
656
  'noprogress': True,
657
- 'merge_output_format': 'mp4'
 
658
  }
659
 
660
- if is_youtube_url:
661
- ydl_opts["cookiefile"] = "firefox-cookies.txt"
662
- '''dl_url = await get_audio_download_url(video_url, quality)
663
- if dl_url and "http" in dl_url:
664
- return {"url": dl_url, "requests_remaining": rate_limiter.max_requests - rate_limiter.get_current_count(user_ip)}
665
- else:
666
- return {
667
- "error": "Failed to Fetch the video."
668
- }
669
- '''
670
- # else:
671
  await run_in_threadpool(lambda: yt_dlp.YoutubeDL(ydl_opts).download([video_url]))
672
-
673
  downloaded_files = list(Path(global_download_dir).glob(f"*_{timestamp}.mp4"))
674
  if not downloaded_files:
675
  return {"error": "Download failed"}
@@ -677,38 +516,12 @@ async def download_high_quality_video(request: Request):
677
  downloaded_file = downloaded_files[0]
678
  encoded_filename = urllib.parse.quote(downloaded_file.name)
679
  download_url = f"{BASE_URL}/file/{encoded_filename}"
680
-
681
-
682
  gc.collect()
 
683
 
684
- return {"url": download_url, "requests_remaining": rate_limiter.max_requests - rate_limiter.get_current_count(user_ip)}
685
-
686
-
687
-
688
-
689
-
690
-
691
-
692
-
693
- api_key_header = APIKeyHeader(name="X-API-Key")
694
-
695
- # Store this securely in your environment variables
696
- API_KEY = os.getenv("API_KEY")
697
-
698
-
699
- async def verify_api_key(api_key: str = Security(api_key_header)):
700
- if api_key != API_KEY:
701
- raise HTTPException(
702
- status_code=403,
703
- detail="Invalid API key"
704
- )
705
- return api_key
706
 
707
  @app.post("/audio")
708
- async def download_audio(
709
- request: Request
710
- #api_key: str = Security(verify_api_key)
711
- ):
712
  user_ip = get_user_ip(request)
713
 
714
  if rate_limiter.is_rate_limited(user_ip):
@@ -722,6 +535,8 @@ async def download_audio(
722
  )
723
  data = await request.json()
724
  video_url = data.get('url')
 
 
725
  #cookiefile = "firefox-cookies.txt"
726
  #env_to_cookies_from_env("firefox-cookies.txt")
727
 
@@ -734,7 +549,6 @@ async def download_audio(
734
  'quiet': True,
735
  'no_warnings': True,
736
  'noprogress': True,
737
- #'cookiefile': cookiefile,
738
  'postprocessors': [{
739
  'key': 'FFmpegExtractAudio',
740
  'preferredcodec': 'mp3',
@@ -742,16 +556,15 @@ async def download_audio(
742
  }]
743
 
744
  }
745
- is_youtube_url = re.search(r'(youtube\.com|youtu\.be)', video_url) is not None
746
  if is_youtube_url:
747
- dl_url = await get_audio_download_url(video_url, 'mp3')
748
  if dl_url and "http" in dl_url:
749
  return {"url": dl_url, "requests_remaining": rate_limiter.max_requests - rate_limiter.get_current_count(user_ip)}
750
  else:
751
  return {
752
- "error": "Failed to Fetch the video."
753
  }
754
- else:
755
  await run_in_threadpool(lambda: yt_dlp.YoutubeDL(ydl_opts).download([video_url]))
756
 
757
  downloaded_files = list(Path(global_download_dir).glob(f"*_{timestamp}.*"))
@@ -766,12 +579,9 @@ async def download_audio(
766
 
767
  # Configure logging
768
  logging.basicConfig(level=logging.INFO)
769
- logger = logging.getLogger(__name__)
770
 
771
  @app.post("/search")
772
- async def search_and_download_song(request: Request,
773
- api_key: str = Security(verify_api_key)
774
- ):
775
  data = await request.json()
776
  song_name = data.get('songname')
777
  artist_name = data.get('artist')
@@ -834,14 +644,3 @@ app.mount("/file", StaticFiles(directory=global_download_dir), name="downloads")
834
 
835
 
836
 
837
-
838
-
839
-
840
-
841
- @app.middleware("http")
842
- async def set_mime_type_middleware(request: Request, call_next):
843
- response = await call_next(request)
844
- if request.url.path.endswith(".mp4"):
845
- response.headers["Content-Type"] = "video/mp4"
846
- return response
847
-
 
29
  import re
30
  import asyncio
31
  import cloudscraper
32
+
 
 
33
 
34
  tmp_dir = tempfile.gettempdir()
35
+ BASE_URL = "https://chrunos-multi.hf.space"
36
+
37
+ logging.basicConfig(level=logging.INFO)
38
+ logger = logging.getLogger(__name__)
39
 
40
 
41
  def env_to_cookies(env_content: str, output_file: str) -> None:
 
127
 
128
 
129
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
130
  # Define a global temporary download directory
131
  global_download_dir = tempfile.mkdtemp()
132
 
133
+ # Rate limiting dictionary
 
134
  class RateLimiter:
135
  def __init__(self, max_requests: int, time_window: timedelta):
136
  self.max_requests = max_requests
 
167
 
168
  # Initialize rate limiter with 100 requests per day
169
  rate_limiter = RateLimiter(
170
+ max_requests=12,
171
  time_window=timedelta(days=1)
172
  )
173
 
 
200
 
201
  # In your function:
202
  api_rotator = ApiRotator([
203
+ "http://109.107.189.229:9000",
204
+ "https://dl01.yt-dl.click",
205
+ "http://34.107.254.11",
206
+ "http://2.56.214.74:9000",
207
  "https://cobalt-api.ayo.tf",
208
+ "https://dwnld.nichind.dev",
209
+ "https://cobalt-api.kwiatekmiki.com"
210
  ])
211
 
212
 
213
 
214
+ async def get_track_download_url(video_url: str, quality: str) -> str:
215
  apis = api_rotator.get_prioritized_apis()
216
  session = cloudscraper.create_scraper() # Requires cloudscraper package
217
  headers = {
 
219
  "Content-Type": "application/json",
220
  "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36"
221
  }
222
+ quality_lower = quality.lower()
223
+ if quality_lower == "mp3":
224
+ body_json = {"url": video_url, "audioFormat": "mp3", "downloadMode": "audio"}
225
+ else:
226
+ body_json = {"url": video_url, "videoQuality": quality, "filenameStyle": "pretty", "youtubeVideoCodec": "h264"}
227
 
228
  for i, api_url in enumerate(apis):
229
  try:
 
232
  response = session.post(
233
  api_url,
234
  timeout=20,
235
+ json=body_json,
236
  headers=headers
237
  )
238
  logger.info(f"Response status: {response.status_code}")
 
242
  json_response = response.json()
243
  error_code = json_response.get("error", {}).get("code", "")
244
 
245
+ if error_code == "error.api.content.video.age":
246
  logger.warning(f"Video unavailable error from {api_url}")
247
  break # Only break for specific error
248
 
 
258
  return {"error": "Download URL not found"}
259
 
260
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
261
 
262
+ restricted_domain = "chrunos.com"
263
+
264
+ @app.post("/maxs")
265
+ async def download_high_quality_video(request: Request):
266
+ user_ip = get_user_ip(request)
267
+
268
+ if rate_limiter.is_rate_limited(user_ip):
269
+ current_count = rate_limiter.get_current_count(user_ip)
270
+ raise HTTPException(
271
+ status_code=429,
272
+ detail={
273
+ "error": "You have exceeded the maximum number of requests per day. Please try again tomorrow.",
274
+ "url": "https://t.me/chrunoss"
275
+ }
276
+ )
277
 
278
+ data = await request.json()
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
279
 
280
+ video_url = data.get('url')
281
+ is_youtube_url = re.search(r'(youtube\.com|youtu\.be)', video_url) is not None
282
+ if "t.me" in video_url or "chrunos.com" in video_url:
283
+ return {"error": f"{video_url} is not supported", "url": "https://t.me/chrunoss"}
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
284
 
285
+ quality = data.get('quality', '720') # Default to 720 if not specified
286
+ logger.info(f'input: {video_url}, {quality}')
287
 
288
+ # Check if the requested quality is above 1080p
289
+ if int(quality) > 720:
290
+ error_message = "Quality above 720p is for Premium Members Only. Please check the URL for more information."
291
+ help_url = "https://chrunos.com/premium-shortcuts/" # Replace with your actual URL
292
+ return {"error": error_message, "url": help_url}
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
293
 
294
+ #cookiefile = "firefox-cookies.txt"
295
+ #env_to_cookies_from_env("firefox-cookies.txt")
296
 
297
+ timestamp = datetime.now().strftime('%Y%m%d%H%M%S')
298
+ output_template = str(Path(global_download_dir) / f'%(title).70s_{timestamp}.%(ext)s')
299
 
300
+ # Convert quality string to height
301
+ height_map = {
302
+ '480': 480,
303
+ '720': 720,
304
+ '1080': 1080
305
+ }
306
+ max_height = height_map.get(quality, 1080) # Use the quality variable correctly
307
 
308
+ # Determine format string based on quality
309
+ format_str = f'bestvideo[height<={max_height}][vcodec^=avc]+bestaudio/best'
310
 
311
+ ydl_opts = {
312
+ 'format': format_str,
313
+ 'outtmpl': output_template,
314
+ 'quiet': True,
315
+ 'no_warnings': True,
316
+ 'noprogress': True,
317
+ 'merge_output_format': 'mp4'
318
+ }
319
 
320
+ if is_youtube_url:
321
+ dl_url = await get_track_download_url(video_url, quality)
322
+ if dl_url and "http" in dl_url:
323
+ return {"url": dl_url, "requests_remaining": rate_limiter.max_requests - rate_limiter.get_current_count(user_ip)}
324
+ else:
325
+ return {
326
+ "error": "Failed to Fetch the video."
327
+ }
328
+ else:
329
+ await run_in_threadpool(lambda: yt_dlp.YoutubeDL(ydl_opts).download([video_url]))
330
+
331
+ downloaded_files = list(Path(global_download_dir).glob(f"*_{timestamp}.mp4"))
332
+ if not downloaded_files:
333
+ return {"error": "Download failed. Report error on Telegram", "url": "https://t.me/chrunoss"}
334
+
335
+ downloaded_file = downloaded_files[0]
336
+ encoded_filename = urllib.parse.quote(downloaded_file.name)
337
+ download_url = f"{BASE_URL}/file/{encoded_filename}"
338
+
339
+
340
+
341
+ gc.collect()
342
+
343
+ return {"url": download_url}
344
 
345
 
346
+ TRACT_API = os.getenv("EXTRACT_API")
347
  ALT_API = os.getenv("ALT_API")
348
 
 
349
  def extract_video_info(video_url: str) -> str:
350
+ if "pornhub.com" in video_url:
351
+ EXTRACT_API = TRACT_API
352
+ else:
353
+ EXTRACT_API = ALT_API
354
+ api_url = f'{EXTRACT_API}?url={video_url}'
355
+ logger.info(api_url)
356
+ session = cloudscraper.create_scraper()
357
+ try:
358
+ response = session.get(api_url, timeout=20)
359
+
360
+ if response.status_code == 200:
361
+ json_response = response.json()
362
+ result = []
363
+ # 检查 formats 列表是否存在且不为空
364
+ if 'formats' in json_response:
365
+ for format_item in json_response['formats']:
366
+ format_url = format_item.get('url')
367
+ format_id = format_item.get('format_id')
368
+ p_cookies = format_item.get('cookies')
369
+ if format_id and format_url:
370
+ result.append({
371
+ "url": format_url,
372
+ "format_id": format_id,
373
+ "cookies": p_cookies
374
+ })
375
+
376
+ title = json_response.get('title')
377
+ logger.info(title)
378
+ if "pornhub.com" in video_url:
379
+ p_result = [item for item in result if 'hls' in item['format_id']]
380
+ last_item = p_result[-1]
381
+ second_last_item = p_result[-2]
382
+ last_item["format_id"] = f'{last_item["format_id"]} - Chrunos Shortcuts Premium Only'
383
+ last_item["url"] = 'https://chrunos.com/premium-shortcuts/'
384
+ second_last_item["format_id"] = f'{second_last_item["format_id"]} - Chrunos Shortcuts Premium Only'
385
+ second_last_item["url"] = 'https://chrunos.com/premium-shortcuts/'
386
+ return p_result
387
  else:
388
+ new_result = result
389
+ # Check if new_result has more than one item
390
+ if len(new_result) > 1:
391
+ # Get the last item
392
+ last_item = new_result[-1]
393
+ # Modify the format_id
394
+ last_item["format_id"] = f'{last_item["format_id"]} - Chrunos Shortcuts Premium Only'
395
+ # Modify the url
396
+ last_item["url"] = 'https://chrunos.com/premium-shortcuts/'
397
+ elif len(new_result) == 1:
398
+ new_item = {"url": "https://chrunos.com/premium-shortcuts/",
399
+ "format_id": "Best Qaulity Video - Chrunos Shortcuts Premium Only"
400
+ }
401
+ new_result.append(new_item)
402
+
403
+ return new_result
404
  else:
405
+ if 'url' in json_response:
406
+ download_url = json_response.get('url')
407
+ thumbnail_url = json_response.get('thumbnail')
408
+ return [
409
+ {"url": download_url,
410
+ "format_id": "Normal Quality Video"
411
+ },
412
+ {"url": thumbnail_url,
413
+ "format_id": "thumbnail"},
414
+ {"url": "https://chrunos.com/premium-shortcuts/",
415
+ "format_id": "Best Qaulity Video - Chrunos Shortcuts Premium Only"}
416
+ ]
417
+ return {"error": "No formats available. Report Error on Telegram"}
418
+ else:
419
+ return {"error": f"Request failed with status code {response.status_code}, API: {api_url}"}
420
+ except Exception as e:
421
+ logger.error(f"An error occurred: {e}")
422
+ return {"error": str(e)}
423
 
424
 
425
  @app.post("/test")
 
446
  'noprogress': True,
447
  'merge_output_format': 'mp4'
448
  }
449
+
450
  try:
451
  await run_in_threadpool(lambda: yt_dlp.YoutubeDL(ydl_opts).download([hls_url]))
452
  except Exception as e:
 
465
 
466
 
467
 
 
 
 
 
 
 
 
 
 
468
 
469
+ @app.post("/max")
470
  async def download_high_quality_video(request: Request):
 
 
 
 
 
 
 
 
 
 
 
 
 
471
  data = await request.json()
 
472
  video_url = data.get('url')
473
+ quality = data.get('quality', '1080') # Default to 1080p if not specified
474
+
 
 
 
 
475
  # Check if the requested quality is above 1080p
476
+ #if int(quality) > 1080:
477
+ # error_message = "Quality above 1080p is for premium users. Please check the URL for more information."
478
+ # help_url = "https://chrunos.com/premium-shortcuts/" # Replace with your actual URL
479
+ # return {"error": error_message, "url": help_url}
480
 
481
  cookiefile = "firefox-cookies.txt"
482
  env_to_cookies_from_env("firefox-cookies.txt")
483
 
484
  timestamp = datetime.now().strftime('%Y%m%d%H%M%S')
485
+ output_template = str(Path(global_download_dir) / f'%(title)s_{timestamp}.%(ext)s')
486
 
487
  # Convert quality string to height
488
  height_map = {
 
 
489
  '480': 480,
490
  '720': 720,
491
+ '1080': 1080,
492
+ '1440': 1440,
493
+ '2160': 2160
494
  }
495
+ max_height = height_map.get(quality, 1080) # Use the quality variable correctly
496
 
497
  # Determine format string based on quality
498
  format_str = f'bestvideo[height<={max_height}][vcodec^=avc]+bestaudio/best'
 
503
  'quiet': True,
504
  'no_warnings': True,
505
  'noprogress': True,
506
+ 'merge_output_format': 'mp4',
507
+ 'cookiefile': cookiefile
508
  }
509
 
 
 
 
 
 
 
 
 
 
 
 
510
  await run_in_threadpool(lambda: yt_dlp.YoutubeDL(ydl_opts).download([video_url]))
511
+
512
  downloaded_files = list(Path(global_download_dir).glob(f"*_{timestamp}.mp4"))
513
  if not downloaded_files:
514
  return {"error": "Download failed"}
 
516
  downloaded_file = downloaded_files[0]
517
  encoded_filename = urllib.parse.quote(downloaded_file.name)
518
  download_url = f"{BASE_URL}/file/{encoded_filename}"
 
 
519
  gc.collect()
520
+ return {"url": download_url}
521
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
522
 
523
  @app.post("/audio")
524
+ async def download_audio(request: Request):
 
 
 
525
  user_ip = get_user_ip(request)
526
 
527
  if rate_limiter.is_rate_limited(user_ip):
 
535
  )
536
  data = await request.json()
537
  video_url = data.get('url')
538
+ is_youtube_url = re.search(r'(youtube\.com|youtu\.be)', video_url) is not None
539
+
540
  #cookiefile = "firefox-cookies.txt"
541
  #env_to_cookies_from_env("firefox-cookies.txt")
542
 
 
549
  'quiet': True,
550
  'no_warnings': True,
551
  'noprogress': True,
 
552
  'postprocessors': [{
553
  'key': 'FFmpegExtractAudio',
554
  'preferredcodec': 'mp3',
 
556
  }]
557
 
558
  }
 
559
  if is_youtube_url:
560
+ dl_url = await get_track_download_url(video_url, 'mp3')
561
  if dl_url and "http" in dl_url:
562
  return {"url": dl_url, "requests_remaining": rate_limiter.max_requests - rate_limiter.get_current_count(user_ip)}
563
  else:
564
  return {
565
+ "error": "Failed to Fetch the audio."
566
  }
567
+ else:
568
  await run_in_threadpool(lambda: yt_dlp.YoutubeDL(ydl_opts).download([video_url]))
569
 
570
  downloaded_files = list(Path(global_download_dir).glob(f"*_{timestamp}.*"))
 
579
 
580
  # Configure logging
581
  logging.basicConfig(level=logging.INFO)
 
582
 
583
  @app.post("/search")
584
+ async def search_and_download_song(request: Request):
 
 
585
  data = await request.json()
586
  song_name = data.get('songname')
587
  artist_name = data.get('artist')
 
644
 
645
 
646