| from pytube import YouTube |
| import yt_dlp |
| import os |
| import argparse |
| |
| |
| |
| from tqdm import tqdm |
| import re |
|
|
| VIDEO_FOLDER = 'videos' |
| AUDIO_FOLDER = 'audios' |
|
|
| DOWNLOAD_VIDEO_NAME = 'download_video' |
| DOWNLOAD_AUDIO_NAME = 'download_audio' |
|
|
| DOWNLOAD_VIDEO_FORMAT = 'mp4' |
| DOWNLOAD_AUDIO_FORMAT = 'mp3' |
|
|
| DOWNLOAD_VIDEO = 'video' |
| DOWNLOAD_AUDIO = 'audio' |
|
|
| def download_twitch(url, type): |
| |
| argparser = argparse.ArgumentParser(description='Download twitch video from URL') |
| argparser.add_argument('--auth-token', default=None, help='Twitch auth token') |
| argparser.add_argument('--chapter', default=None, help='Chapter to download') |
| argparser.add_argument('--debug', default=False, help='Debug', action='store_true') |
| argparser.add_argument('--end', default=None, help='End') |
| argparser.add_argument('--format', default=f'{DOWNLOAD_VIDEO_FORMAT}', help='Format') |
| argparser.add_argument('--keep', default=False, help='Keep', action='store_true') |
| argparser.add_argument('--max_workers', default=5, help='Max workers') |
| argparser.add_argument('--no_color', default=False, help='No color', action='store_true') |
| argparser.add_argument('--no_join', default=False, help='No join', action='store_true') |
| argparser.add_argument('--output', default=f'{VIDEO_FOLDER}/{DOWNLOAD_VIDEO_NAME}.{format}', help='Output') |
| argparser.add_argument('--overwrite', default=False, help='Overwrite', action='store_true') |
| argparser.add_argument('--quality', default=None, help='Quality') |
| argparser.add_argument('--rate_limit', default=None, help='Rate limit') |
| argparser.add_argument('--start', default=None, help='Start') |
| argparser.add_argument('--version', default=False, help='Version', action='store_true') |
| argparser.add_argument('videos', default=[url], help='Videos', nargs='+') |
| args = argparser.parse_args() |
|
|
| |
| video_id = re.search(r'(?<=videos\/)\d+', url).group(0) |
|
|
| |
| access_token = twitchdl.twitch.get_access_token(video_id, None) |
| playlists_m3u8 = twitchdl.twitch.get_playlists(video_id, access_token) |
| playlists = list(_parse_playlists(playlists_m3u8)) |
| qualitys = [name for (name, _, _) in playlists] |
|
|
| |
| if type == DOWNLOAD_VIDEO: |
| args.quality = qualitys[0] |
| args.format = DOWNLOAD_VIDEO_FORMAT |
| args.output = f'{VIDEO_FOLDER}/{DOWNLOAD_VIDEO_NAME}.{args.format}' |
| elif type == DOWNLOAD_AUDIO: |
| args.quality = qualitys[-1] |
| args.format = "mkv" |
| args.output = f'{AUDIO_FOLDER}/{DOWNLOAD_AUDIO_NAME}.{args.format}' |
|
|
| |
| twitch_downloader.download(args) |
| if type == DOWNLOAD_AUDIO: |
| os.system(f'ffmpeg -i {AUDIO_FOLDER}/{DOWNLOAD_AUDIO_NAME}.{args.format} -c:a libmp3lame -b:a 192k -stats -loglevel warning {AUDIO_FOLDER}/{DOWNLOAD_AUDIO_NAME}.{DOWNLOAD_AUDIO_FORMAT}') |
| os.system(f'rm {AUDIO_FOLDER}/{DOWNLOAD_AUDIO_NAME}.{args.format}') |
|
|
| def create_minimal_cookies(): |
| cookies_content = """# Netscape HTTP Cookie File |
| # https://www.youtube.com/ |
| .youtube.com TRUE / FALSE 1735689600 CONSENT YES+cb |
| .youtube.com TRUE / FALSE 1735689600 VISITOR_INFO1_LIVE random_string |
| """ |
| with open('youtube_cookies.txt', 'w') as f: |
| f.write(cookies_content) |
| return 'youtube_cookies.txt' |
|
|
| def download_youtube_video(url): |
| try: |
| cookies_file = create_minimal_cookies() |
| |
| ydl_options = { |
| "outtmpl": f"{VIDEO_FOLDER}/{DOWNLOAD_VIDEO_NAME}.{DOWNLOAD_VIDEO_FORMAT}", |
| "format": "best", |
| "user_agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36", |
| "force_ipv4": True, |
| "no_check_certificates": True, |
| "geo_bypass": True, |
| "cookiefile": cookies_file |
| } |
| |
| with yt_dlp.YoutubeDL(ydl_options) as ydl: |
| ydl.download(url) |
| except Exception as e: |
| print(f'Error descargando el video: {str(e)}') |
|
|
| def download_youtube_audio(url): |
| try: |
| cookies_file = create_minimal_cookies() |
| |
| ydl_options = { |
| "outtmpl": f"{AUDIO_FOLDER}/{DOWNLOAD_AUDIO_NAME}.{DOWNLOAD_AUDIO_FORMAT}", |
| "format": "bestaudio", |
| "user_agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36", |
| "force_ipv4": True, |
| "no_check_certificates": True, |
| "geo_bypass": True, |
| "cookiefile": cookies_file |
| } |
| |
| with yt_dlp.YoutubeDL(ydl_options) as ydl: |
| ydl.download(url) |
| except Exception as e: |
| print(f'Error descargando el audio: {str(e)}') |
|
|
| def download_youtube(url, type): |
| if type == DOWNLOAD_VIDEO: |
| download_youtube_video(url) |
| elif type == DOWNLOAD_AUDIO: |
| download_youtube_audio(url) |
| else: |
| print('Unknown youtube download type') |
|
|
| def main(args): |
| url = args.url |
| num_works = 2 |
| download_progress_bar = tqdm(total=num_works, desc='Downloading video and audio progress') |
| if 'twitch' in url.lower(): |
| download_twitch(url, DOWNLOAD_VIDEO) |
| download_progress_bar.update(1) |
| download_twitch(url, DOWNLOAD_AUDIO) |
| download_progress_bar.update(1) |
| elif 'youtube' in url.lower() or 'youtu.be' in url.lower(): |
| download_youtube(url, DOWNLOAD_VIDEO) |
| download_progress_bar.update(1) |
| download_youtube(url, DOWNLOAD_AUDIO) |
| download_progress_bar.update(1) |
| else: |
| print('Unknown video source') |
|
|
| if __name__ == "__main__": |
| argparser = argparse.ArgumentParser(description='Download video from URL') |
| argparser.add_argument('url', help='URL of video') |
| args = argparser.parse_args() |
| main(args) |