def check_available(self) -> bool: # directly use the search extractors entry function so we can process each result # as soon as it's available instead of waiting for all of them extractor = yt_dlp.extractor.youtube.YoutubeSearchIE() extractor._downloader = yt_dlp.YoutubeDL(self.ydl_opts) extractor.initialize() for entry in extractor._search_results(self.query): if song_utils.is_forbidden(entry["title"]): continue try: with yt_dlp.YoutubeDL(self.ydl_opts) as ydl: self.info_dict = ydl.extract_info(entry["id"], download=False) break except (yt_dlp.utils.ExtractorError, yt_dlp.utils.DownloadError) as error: logging.warning("error during availability check for %s:", entry["id"]) logging.warning(error) else: self.error = "No songs found" return False self.id = self.info_dict["id"] return self.check_not_too_large(self.info_dict["filesize"])
def download_video(self, queue: YoutubeQueue): # Download audio part default_audio_name = "audio" audio_file = queue.save_location + "\\" + default_audio_name output_file_path = audio_file + '.%(ext)s' ydl_opts = self.build_audio_fragment_download_options(output_file_path) with youtube_dl.YoutubeDL(ydl_opts) as ydl: ydl.download([queue.link]) result = ydl.extract_info("{}".format(queue.link)) queue.audio_dl_stats = copy.deepcopy(self.download_stats) # Download video part (has no sound) default_video_name = "video" video_file = queue.save_location + "\\" + default_video_name output_file_path = video_file + '.%(ext)s' ydl_opts = self.build_video_fragment_download_options(output_file_path) with youtube_dl.YoutubeDL(ydl_opts) as ydl: ydl.download([queue.link]) result = ydl.extract_info("{}".format(queue.link)) queue.video_dl_stats = copy.deepcopy(self.download_stats) # Replace tags from file_name by its values from queue.video_dl_stats queue.replace_file_name_tags() # Merge audio and video parts to single file audio_file = default_audio_name + "." + constants.M4A video_file_extension = File.get_file_name_with_extension(queue.save_location, default_video_name).split(".")[-1] video_file = default_video_name + "." + video_file_extension merged_file = queue.file_name + "." + queue.save_format Ffmpeg.merge_audio_and_video(queue.save_location, audio_file, video_file, merged_file)
async def process_playlist(self, playlist_type, url): if playlist_type == linkutils.Playlist_Types.YouTube_Playlist: if ("playlist?list=" in url): listid = url.split('=')[1] else: video = url.split('&')[0] await self.process_song(video) return options = { 'format': 'bestaudio/best', 'extract_flat': True, "cookiefile": config.COOKIE_PATH } with yt_dlp.YoutubeDL(options) as ydl: r = ydl.extract_info(url, download=False) for entry in r['entries']: link = "https://www.youtube.com/watch?v={}".format( entry['id']) song = Song(linkutils.Origins.Playlist, linkutils.Sites.YouTube, webpage_url=link) self.playlist.add(song) if playlist_type == linkutils.Playlist_Types.Spotify_Playlist: links = await linkutils.get_spotify_playlist(url) for link in links: song = Song(linkutils.Origins.Playlist, linkutils.Sites.Spotify, webpage_url=link) self.playlist.add(song) if playlist_type == linkutils.Playlist_Types.BandCamp_Playlist: options = {'format': 'bestaudio/best', 'extract_flat': True} with yt_dlp.YoutubeDL(options) as ydl: r = ydl.extract_info(url, download=False) for entry in r['entries']: link = entry.get('url') song = Song(linkutils.Origins.Playlist, linkutils.Sites.Bandcamp, webpage_url=link) self.playlist.add(song) for song in list(self.playlist.playque)[:config.MAX_SONG_PRELOAD]: asyncio.ensure_future(self.preload(song))
def single_songs(urls: List[str], artist, album, info_opts, download_opts, track_numbers, strip_patterns, **kwargs) -> None: if len(urls) == 1: print( "\nthis video is not a playlist, and it has no chapters, are you sure you want to proceed?" ) text = capture_input("(y)es, (n)o: ", "y", "n") if text == "n": try: os.rmdir(os.getcwd()) except Exception: pass print("\nexiting...") sys.exit(0) status = [] tracks = parse_track_numbers(track_numbers) if tracks and len(urls) != len(tracks): sys.exit("you passed {} track(s) and {} url(s)".format( len(tracks), len(urls))) for i, url in enumerate(urls): idx = tracks[i] if tracks else i + 1 with youtube_dl.YoutubeDL(info_opts) as ydl: info = ydl.extract_info(url, download=False) if not info: status.append((idx, False, "", "")) continue if not glob.glob("*{}.*".format(info["id"])): # don't redownload file with youtube_dl.YoutubeDL(download_opts) as ydl: ydl.download([url]) else: print( "\nfound matching file for {}... if you wish to download and process file again, " "delete this file, or delete album directory\n".format( info["title"])) title = strip(info["title"], strip_patterns) or info["title"] for file in glob.glob("*{}.*".format(info["id"])): _, extension = os.path.splitext(file) set_audio_id3(file, title=title, artist=artist, album=album, tracknumber="{}/{}".format(idx, len(urls))) try: os.rename(file, "{}-{}{}".format(title, info["id"], extension)) except Exception: pass status.append((idx, True, info["id"], info["title"])) print("\n{}\n".format("\n".join(format_status_with_url(s) for s in status)))
def download(item): mp3_postprocessor = { 'key': 'FFmpegExtractAudio', 'preferredcodec': 'mp3', 'preferredquality': '0', } opus_postprocessor = { 'key': 'FFmpegExtractAudio', 'preferredcodec': item.ext, } metadata_postprocessor = {'key': 'FFmpegMetadata', 'add_metadata': True} ydl_opts = { 'format': 'bestaudio/best', 'paths': { 'home': '/downloads/' }, 'outtmpl': '%(artist)s-%(album)s-%(track)s-[%(id)s]-(%(title)s).%(ext)s' } if item.ext == 'mp3': ydl_opts['postprocessors'] = [ mp3_postprocessor, metadata_postprocessor ] if item.ext in ['opus', 'ogg', 'webm']: ydl_opts['postprocessors'] = [ opus_postprocessor, metadata_postprocessor ] if item.url is not None: print("Starting download of " + item.url) with yt_dlp.YoutubeDL(ydl_opts) as ydl: ydl.add_post_processor(AddID3ArtworkPP()) ydl.download([item.url]) print("Finished downloading " + item.url) else: print(f'Starting download {item.artist}-{item.title}') if item.artist is not None and item.album is not None: ydl_opts['paths'][ 'home'] = f'/downloads/{item.artist}/{item.album}/' with yt_dlp.YoutubeDL(ydl_opts) as ydl: ydl.add_post_processor(AddID3ArtworkPP()) ydl.extract_info( f'ytsearch:{item.artist} {item.title} Lyric Video', extra_info={'artwork': item.artwork}) print(f'Finished downloading {item.artist}-{item.title}')
def __init__(self, download_folder=None): self.thread_pool = ThreadPoolExecutor(max_workers=2) self.download_folder = download_folder if download_folder: # print("setting template to " + os.path.join(download_folder, otmpl)) otmpl = ytdl_format_options["outtmpl"] ytdl_format_options["outtmpl"] = os.path.join(download_folder, otmpl) self.unsafe_ytdl = youtube_dl.YoutubeDL(ytdl_format_options) self.safe_ytdl = youtube_dl.YoutubeDL( {**ytdl_format_options, "ignoreerrors": True} )
async def play_song(self, song): """Plays a song object""" if self.playlist.loop != True: #let timer run thouh if looping self.timer.cancel() self.timer = utils.Timer(self.timeout_handler) if song.info.title == None: if song.host == linkutils.Sites.Spotify: conversion = self.search_youtube(await linkutils.convert_spotify(song.info.webpage_url)) song.info.webpage_url = conversion try: downloader = yt_dlp.YoutubeDL( {'format': 'bestaudio', 'title': True, "cookiefile": config.COOKIE_PATH}) r = downloader.extract_info( song.info.webpage_url, download=False) except: asyncio.wait(1) downloader = yt_dlp.YoutubeDL( {'title': True, "cookiefile": config.COOKIE_PATH}) r = downloader.extract_info( track, download=False) song.base_url = r.get('url') song.info.uploader = r.get('uploader') song.info.title = r.get('title') song.info.duration = r.get('duration') song.info.webpage_url = r.get('webpage_url') song.info.thumbnail = r.get('thumbnails')[0]['url'] self.playlist.add_name(song.info.title) self.current_song = song self.playlist.playhistory.append(self.current_song) self.guild.voice_client.play(discord.FFmpegPCMAudio( song.base_url, before_options='-reconnect 1 -reconnect_streamed 1 -reconnect_delay_max 5'), after=lambda e: self.next_song(e)) self.guild.voice_client.source = discord.PCMVolumeTransformer( self.guild.voice_client.source) self.guild.voice_client.source.volume = float(self.volume) / 100.0 self.playlist.playque.popleft() for song in list(self.playlist.playque)[:config.MAX_SONG_PRELOAD]: asyncio.ensure_future(self.preload(song))
def get_mp3(url): global payload if not is_supported(url): return {"msg": "That video url didn't work.\n" "https://media.giphy.com/media/SFkjp1R8iRIWc/giphy.gif", "file": "" } payload = {} ydl_opts = { 'format': 'bestaudio/best', 'restrictfilenames': True, 'outtmpl': f'{storage.absolute()}/%(title).50s.%(ext)s', 'forcefilename': True, 'ffmpeg_location': '/app/vendor/ffmpeg/ffmpeg', 'postprocessors': [{ 'key': 'FFmpegExtractAudio', 'preferredcodec': 'mp3', 'preferredquality': '192', }], 'logger': MyLogger(), 'progress_hooks': [my_hook], } with yt_dlp.YoutubeDL(ydl_opts) as ydl: ydl.add_post_processor(MyCustomPP()) info = ydl.extract_info(url) # print(json.dumps(ydl.sanitize_info(info))) return payload
def get_mp4(url): global info global payload info = {} payload = {} if not is_supported(url): return {"msg": "That video url didn't work.\n" "https://media.giphy.com/media/SFkjp1R8iRIWc/giphy.gif", "file": "" } ydl_opts = { 'format': 'bestvideo[ext=mp4]+bestaudio[ext=m4a]/best[ext=mp4]/best', 'restrictfilenames': True, # 'outtmpl': f'{storage.absolute()}/%(title)s.%(format_id)s.%(ext)s', 'outtmpl': f'{storage.absolute()}/%(title).50s.%(ext)s', 'windowsfilenames': True, 'ffmpeg_location': '/app/vendor/ffmpeg/ffmpeg', 'logger': MyLogger(), 'progress_hooks': [my_hook], } with yt_dlp.YoutubeDL(ydl_opts) as ydl: ydl.add_post_processor(MyCustomPP()) yt_info = ydl.extract_info(url) # pprint(yt_info) # pprint(ydl.sanitize_info(yt_info)) return payload
def auto_poster(self, url, author, group_id, directory, album_id=None, wall_post=1): ydl_opts = { 'outtmpl': f"../{directory}/%(title)s.%(ext)s", 'quiet': True, 'merge_output_format': 'mp4', 'ignoreerrors': True, 'format': "(((bv*[fps>30]/bv*)/(wv*[fps>30]/wv*)) + ba / (b[fps>30]/b)/(w[fps>30]/w))[format_id!=22]", 'retries': 10 } try: with yt_dlp.YoutubeDL(ydl_opts) as ydl: ydl.download([url]) video_info = ydl.extract_info(url, download=False) path = ydl.prepare_filename(video_info) title = video_info.get('title') id_vk, name_vk = self.upload("{" + author + "} " + title, path, group_id, album_id=album_id, wall_post=wall_post) return id_vk, name_vk except Exception as e: print("ОШИБКА " + str(e)) print() finally: time.sleep(5) os.remove(path)
def download_video(url, captions, auto_captions, legacy): '''Try to download YouTube video in specific resolution. Fall back to bestvideo+bestaudio/best if not available in target resolution. ''' ydl_opts = YDL_COMMON_OPTS.copy() ydl_opts.update(YDL_OPTS_SPECIFIC_RES) if args.skip_encoding: pass elif auto_captions: ydl_opts.update({'writeautomaticsub': True}) elif captions: ydl_opts.update({'writesubtitles': True}) while True: if legacy: with youtube_dl.YoutubeDL(ydl_opts) as ydl: try: ydl.download([url]) break except youtube_dl.utils.DownloadError as e: if 'not available' in str(e): log.warning('Resolution {res} not available, downloading best possible resolution.'.format(res=args.res)) ydl_opts.update(YDL_OPTS_BEST_RES) else: with yt_dlp.YoutubeDL(ydl_opts) as ydl: try: ydl.download([url]) break except yt_dlp.utils.DownloadError as e: if 'not available' in str(e): log.warning('Resolution {res} not available, downloading best possible resolution.'.format(res=args.res)) ydl_opts.update(YDL_OPTS_BEST_RES)
def downloadYouTube(self, fileName, destinationDirectory, link): tempFilePath = os.path.join(DL_DIRECTORY, fileName) destinationPath = os.path.join(destinationDirectory, fileName) options = { 'format': 'bestvideo[ext=mp4]+bestaudio[ext=m4a]', 'default_search': 'auto', 'restrictfilenames': True, 'prefer_ffmpeg': True, 'quiet': True, 'no_warnings': True, 'ignoreerrors': True, 'noplaylist': True, 'noprogress': True, 'logger': logger.get_null_log('YouTube-DL'), 'outtmpl': tempFilePath } log.info('Attempting to download video: {} from "{}". Please Wait...'. format(fileName, link)) try: with yt_dlp.YoutubeDL(options) as youtube: youtube.extract_info(link, download=True) except Exception as e: log.warning( 'Something went wrong while getting trailer from {}. ERROR: {}' .format(link, e)) return False if os.path.isfile(tempFilePath): self._moveTo(tempFilePath, destinationPath) return True else: log.warning('Failed to download from {}'.format(link)) return False
async def download(self, url: str, filePath: pathlib.Path): try: self._current = url settings = YOUTUBE_DL_OPTIONS settings["outtmpl"] = str(filePath) try: with youtube_dl.YoutubeDL(settings) as youtube: self.log("Downloading {} to {}".format(url, filePath)) with ThreadPoolExecutor() as pool: loop = asyncio.get_running_loop() await loop.run_in_executor( pool, lambda: youtube.extract_info(url, download=True)) self.log("Finished downloading {} to {}".format( url, filePath)) except Exception as exception: self.error("Error downloading {}\n{}".format(url, exception)) finally: self._current = ""
def fetch_metadata(url): stdout = io.StringIO() stderr = io.StringIO() info = None with yt_dlp.YoutubeDL({'extract_flat': 'in_playlist'}) as ydl: ydl.params['extract_flat'] = 'in_playlist' return ydl.extract_info(url, download=False)
def _tubeDl(url: str, starttime, uid: str): ydl_opts = { "addmetadata": True, "geo_bypass": True, "nocheckcertificate": True, "outtmpl": os.path.join( Config.TEMP_DIR, str(starttime), "%(title)s-%(format)s.%(ext)s" ), # "logger": LOGS, "format": uid, "writethumbnail": True, "prefer_ffmpeg": True, "postprocessors": [ {"key": "FFmpegMetadata"} # ERROR R15: Memory quota vastly exceeded # {"key": "FFmpegVideoConvertor", "preferedformat": "mp4"}, ], "quiet": True, } try: with yt_dlp.YoutubeDL(ydl_opts) as ydl: x = ydl.download([url]) except DownloadError as e: LOGS.error(e) except GeoRestrictedError: LOGS.error( "ERROR: The uploader has not made this video available in your country" ) else: return x
def run(self): """ Defines options to extract_info with youtube_dl """ mylogger = MyLogger() ydl_opts = { 'ignoreerrors': True, 'noplaylist': True, 'no_color': True, 'nocheckcertificate': self.nocheckcertificate, 'logger': mylogger, } if self.appdata['downloader'] == 'youtube_dl': with youtube_dl.YoutubeDL(ydl_opts) as ydl: meta = ydl.extract_info(self.url, download=False) elif self.appdata['downloader'] == 'yt_dlp': with yt_dlp.YoutubeDL(ydl_opts) as ydl: meta = ydl.extract_info(self.url, download=False) error = mylogger.get_message() if error: self.data = (None, error) elif meta: self.data = (meta, None) wx.CallAfter(pub.sendMessage, "RESULT_EVT", status='')
async def _add_playlist(self, ctx, *, url): """Adds all songs in a playlist to the queue""" if len(url) > 100: raise ValueError("url too long (length over 100)") if not url.isprintable(): raise ValueError(f"url not printable: {url!r}") print(ctx.message.author.name, "queued playlist", repr(url)) bracketed = False if url[0] == "<" and url[-1] == ">": bracketed = True url = url[1:-1] info = self.get_info(ctx) queue = info["queue"] ytdl = youtube_dl.YoutubeDL(self.ytdl_opts | { 'noplaylist': None, 'playlistend': None, "extract_flat": True, }) data = await asyncio.to_thread(ytdl.extract_info, url, download=False) if 'entries' not in data: raise ValueError("cannot find entries of playlist") entries = data['entries'] for entry in entries: url = f"https://www.youtube.com/watch?v={entry['url']}" if bracketed: url = f"<{url}>" queue.append({"ty": "stream", "query": url}) if info["current"] is None: self.schedule(ctx) await ctx.send(f"Added playlist to queue: {url}")
def youtube_session() -> Iterator[requests.Session]: """This context opens a requests session and loads the youtube cookies file.""" cookies_path = os.path.join(settings.BASE_DIR, "config/youtube_cookies.pickle") session = requests.session() # Have yt-dlp deal with consent cookies etc to setup a valid session extractor = yt_dlp.extractor.youtube.YoutubeIE() extractor._downloader = yt_dlp.YoutubeDL() extractor.initialize() session.cookies.update(extractor._downloader.cookiejar) try: if os.path.getsize(cookies_path) > 0: with open(cookies_path, "rb") as cookies_file: session.cookies.update(pickle.load(cookies_file)) except FileNotFoundError: pass headers = {"User-Agent": yt_dlp.utils.random_user_agent()} session.headers.update(headers) yield session with open(cookies_path, "wb") as cookies_file: pickle.dump(session.cookies, cookies_file)
def extract_tracks(user_playlist: UserPlaylist) -> UserPlaylist: playlist_url = UriParser(user_playlist.uri).url with yt_dlp.YoutubeDL(YTDL_OPTS) as ytdl: playlist_infos = ytdl.extract_info(playlist_url, download=False, process=False) if not playlist_infos: user_playlist.title = "⚠️ Invalid or private playlist" user_playlist.enabled = False user_playlist.save() return user_playlist all_track_uris = [] for video in playlist_infos['entries']: track_uri = make_track_uri(video) user_track, user_track_created = UserTrack.objects.get_or_create( track_uri=track_uri, user_playlist=user_playlist, defaults={'date_added': timezone.now()}, ) all_track_uris.append(track_uri) # Delete records that are missing from the current version of the playlist UserTrack.objects.filter(user_playlist=user_playlist).exclude( track_uri__in=all_track_uris).delete() user_playlist.title = playlist_infos['title'] return user_playlist
def make_track_uri(video): track_uri, track_uri_created = TrackUri.objects.get_or_create( uri=f'youtube:video:{video["id"]}', ) # Videos that are private or deleted appear without an uploader track_uri.deleted = not video["uploader"] # Retry to fetch unavailable track info to check if it's still unavailable if track_uri.unavailable: with yt_dlp.YoutubeDL(YTDL_OPTS) as ytdl: track_uri.unavailable = ( not track_uri.deleted and not ytdl.extract_info(UriParser(track_uri.uri).url, download=False, process=False)) if not track_uri.deleted and not track_uri.track: artist_without_topic = re.sub(' - [Tt]opic$', '', video['uploader']) track_uri.track = Track.objects.create( title=video['title'], artist=artist_without_topic, duration=timedelta(seconds=int(video['duration'])), ) track_uri.save() return track_uri
async def play(ctx, url): voice = discord.utils.get(bot.voice_clients, guild=ctx.guild) if ctx.voice_client is None: channel = ctx.author.voice.channel await channel.connect() ydl_opts = {'format': 'bestaudio'} server = ctx.message.guild voice_channel = server.voice_client FFMPEG_OPTIONS = { 'before_options': '-reconnect 1 -reconnect_streamed 1 -reconnect_delay_max 5', 'options': 'vn' } if not voice_channel.is_playing(): with yt_dlp.YoutubeDL(ydl_opts) as ydl: info = ydl.extract_info(url, download=False) url2 = info['formats'][0]['url'] print(url2) voice_channel.play(FFmpegPCMAudio(source=url2, **FFMPEG_OPTIONS)) voice_channel.is_playing() else: await ctx.send("Cekaj da se zavrsi play ili kucaj '!stop'.") return
def run(self): """ This atipic method is called by start() method after the instance this class. see Streaming class below. """ if self.stop_work_thread: return ydl_opts = { 'format': self.quality, 'outtmpl': f'{self.outputdir}/{self.outtmpl}', 'restrictfilenames': True, 'nopart': True, # see --no-part by --help 'ignoreerrors': True, 'continue': True, 'no_warnings': False, 'noplaylist': True, 'no_color': True, 'nocheckcertificate': self.nocheckcertificate, 'ffmpeg_location': f'{DownloadStream.FFMPEG_URL}', 'logger': MyLogger(), } if DownloadStream.DOWNLOADER == 'yt_dlp': with yt_dlp.YoutubeDL(ydl_opts) as ydl: ydl.download([f"{self.url}"]) elif DownloadStream.DOWNLOADER == 'youtube_dl': with youtube_dl.YoutubeDL(ydl_opts) as ydl: ydl.download([f"{self.url}"])
def download_clip(url): video_info = {} ydl_opts = { 'format': 'best', #2 71 - 2560x1440 (1440p) #313 - 3840x2160 (2160p) #248 - 1920x1080 (1080p) 'outtmpl': '%(id)s.%(ext)s', 'writethumbnail': True, # Download Thumbnail 'proxy': os.getenv('PROXY') } try: with yt_dlp.YoutubeDL(ydl_opts) as ydl: info_dict = ydl.extract_info(url, download=False) video_info["title"] = info_dict.get("title") video_info["cover"] = info_dict.get("thumbnail") video_info["link"] = info_dict.get("webpage_url") video_info["video_path"] = "%s.%s" % (info_dict["display_id"], info_dict["ext"]) video_info["cover_path"] = "%s.%s" % (info_dict["display_id"], "jpg") ydl.download([url]) im = Image.open("%s.%s" % (info_dict["display_id"], "webp")).convert("RGB") im.save("%s.%s" % (info_dict["display_id"], "jpg"), "jpeg") logger.info("Successfully Download", [url]) return video_info except Exception as e: print(e) return False
def get_media_info(url): ''' Extracts information from a YouTube URL and returns it as a dict. For a channel or playlist this returns a dict of all the videos on the channel or playlist as well as associated metadata. ''' opts = get_yt_opts() opts.update({ 'skip_download': True, 'forcejson': True, 'simulate': True, 'logger': log, 'extract_flat': True, }) response = {} with yt_dlp.YoutubeDL(opts) as y: try: response = y.extract_info(url, download=False) except yt_dlp.utils.DownloadError as e: raise YouTubeError(f'Failed to extract_info for "{url}": {e}') from e if not response: raise YouTubeError(f'Failed to extract_info for "{url}": No metadata was ' f'returned by youtube-dl, check for error messages in the ' f'logs above. This task will be retried later with an ' f'exponential backoff.') return response
def _mp3Dl(url: str, starttime, uid: str): _opts = { "outtmpl": os.path.join(Config.TEMP_DIR, str(starttime), "%(title)s.%(ext)s"), # "logger": LOGS, "writethumbnail": True, "prefer_ffmpeg": True, "format": "bestaudio/best", "geo_bypass": True, "nocheckcertificate": True, "postprocessors": [ { "key": "FFmpegExtractAudio", "preferredcodec": "mp3", "preferredquality": uid, }, {"key": "EmbedThumbnail"}, # ERROR: Conversion failed! {"key": "FFmpegMetadata"}, ], "quiet": True, } try: with yt_dlp.YoutubeDL(_opts) as ytdl: dloader = ytdl.download([url]) except Exception as y_e: LOGS.exception(y_e) return y_e else: return dloader
async def youtube_dl_query(self, query, offset=None, limit=None): logger.debug(f"youtube_dl_query: {query} {offset}, {limit}") ytdl_opts = { # "ignoreerrors": False, 'quiet': True, 'no_color': True, 'extract_flat': "in_playlist", "playlistend": limit, 'proxy': self.proxies.get("https", None) if self.proxies else None, 'logger': logger } if offset: ytdl_opts["playliststart"] = offset + 1 ytdl_opts["playlistend"] = offset + limit # ytdl_opts["daterange"] = youtube_dl.DateRange(end=) with youtube_dl.YoutubeDL(ytdl_opts) as ydl: playlist_dict = ydl.extract_info(query, download=False) if not playlist_dict: logger.warn("youtube_dl returned no data") return for item in playlist_dict['entries']: yield AttrDict( guid=item["id"], title=item["title"], duration_seconds=item["duration"], )
def getVideoInfo(id, audioonly): log("Retrieving Metadata for Video " + id) url = "https://youtube.com/watch?v=" + id if audioonly: options = { 'format': 'bestaudio/best', 'postprocessors': [{ 'key': 'FFmpegExtractAudio', 'preferredcodec': 'mp3' }] } else: options = { 'format': 'bestvideo[ext=mp4]+bestaudio[ext=m4a]/best', } ydl = yt_dlp.YoutubeDL(options) info = ydl.extract_info(url, download=False) title = info.get("title", "") log("Title: " + title) size = info.get('filesize', 0) for f in info.get("requested_formats", []): size += f["filesize"] log("Size: " + str(size) + " Bytes") task_handler.add_task(id, title, audioonly, size)
def _worker( input_queue: Queue, output_queue: Queue, output_folder, info_folder, *, cookiefile=None, verbose=False, timeout=5, ): ydl_opts = { 'format': 'bestaudio/best', 'outtmpl': str(output_folder / '%(id)s_temp.%(ext)s'), 'quiet': True, 'no_warnings': True, 'socket_timeout': timeout, } if cookiefile is not None: ydl_opts['cookiefile'] = cookiefile with suppress_stderr(), yt_dlp.YoutubeDL(ydl_opts) as ydl: while not input_queue.empty(): clips = input_queue.get() for clip_id, start, end in clips: try: _download_clip(clip_id, start, end, ydl, output_folder, info_folder) output_queue.put((clip_id, True)) except Exception as ex: if verbose: print( str(clip_id) + " --> " + str(type(ex)) + ": " + str(ex)) output_queue.put((clip_id, False))
def get_and_send_videos(msg: tg.Message, urls: list[str], gif: bool = False): logger.info(f"[{msg.message_id}] {', '.join(urls)}") opts: dict = YDL_OPTS if not gif else YDL_OPTS_GIF try: if trim := parse_timestamp(msg): opts["postprocessors"].append(trim) except InternalError as e: logger.error(f"[{msg.message_id}] {e.msg}") msg.reply_text(f"{e.msg}\nid: {msg.message_id}", quote=True, disable_web_page_preview=True) return with yt_dlp.YoutubeDL(opts) as ydl: for url in urls: ydl.cache.remove() fn = "" try: info = ydl.extract_info(url, download=True) v_id = info["id"] fn = ydl.prepare_filename(info) if trim: fn += ".trim.mp4" except Exception as e: logger.error(f"[{msg.message_id}] {type(e)}: {e}") msg.reply_text(f"Unable to find video at {url}\nid: {msg.message_id}", quote=True, disable_web_page_preview=True) else: send_videos(msg, url, fn, v_id, gif) f = Path(fn) if f.is_file(): f.unlink()
def fetch_metadata(self) -> bool: # in case of a radio playlist, restrict the number of songs that are downloaded assert self.id if self.is_radio(): self.ydl_opts["playlistend"] = storage.get("max_playlist_items") # radios are not viewable with the /playlist?list= url, # create a video watch url with the radio list query_url = ("https://www.youtube.com/watch?v=" + self.id[2:] + "&list=" + self.id) else: # if only given the id, yt-dlp returns an info dict resolving this id to a url. # we want to receive the playlist entries directly, so we query the playlist url query_url = "https://www.youtube.com/playlist?list=" + self.id try: with yt_dlp.YoutubeDL(self.ydl_opts) as ydl: info_dict = ydl.extract_info(query_url, download=False) except (yt_dlp.utils.ExtractorError, yt_dlp.utils.DownloadError) as error: self.error = error return False if info_dict["_type"] != "playlist" or "entries" not in info_dict: # query was not a playlist url -> search for the query assert False assert self.id == info_dict["id"] if "title" in info_dict: self.title = info_dict["title"] for entry in info_dict["entries"]: self.urls.append("https://www.youtube.com/watch?v=" + entry["id"]) assert self.key is None return True