import sys
-from .funcmodule import check_playlist, get_audio_metadata_streams, download_audio_streams
-
+from .funcmodule import check_playlist, get_audio_metadata_stream, download_audio_stream
+import concurrent.futures
def main():
links = check_playlist(links)
assert len(links) > 0, "Should be at least one song in playlist"
- print("Getting audio streams and metadata")
- streams, metadata = get_audio_metadata_streams(links)
- assert len(streams) > 0, "was not able to get audio streams / metadata"
- assert len(metadata) == len(streams), "make sure metadata for every stream"
+ audio_streams = []
+ metadata_list = []
+
+ for link in links:
+ stream, metadata = get_audio_metadata_stream(link)
+ assert stream is not None, "was not able to get audio stream"
+ assert metadata is not None, "no metadata found"
+ audio_streams.append(stream)
+ metadata_list.append(metadata)
- if arg == "-d":
+ assert len(audio_streams) > 0, "no audio streams found"
+ assert len(metadata_list) > 0, "no metadata found"
+
+ if mode == "-d":
pass
- elif arg == "-a":
- print("Downloading audio streams")
- download_audio_streams(streams, metadata)
- elif arg == "-v":
+ elif mode == "-a":
+ # Use ThreadPoolExecutor to run downloads concurrently
+ with concurrent.futures.ThreadPoolExecutor() as executor:
+ # Schedule the download_audio_stream function for each audio stream
+ futures = {executor.submit(download_audio_stream, stream, metadata): stream for stream, metadata in
+ zip(audio_streams, metadata_list)}
+
+ # Optionally, you can wait for completion and handle exceptions
+ for future in concurrent.futures.as_completed(futures):
+ stream = futures[future]
+ try:
+ future.result() # This will raise an exception if the function raised one
+ except Exception as e:
+ print(f"Error downloading {stream.title}: {e}")
+ elif mode == "-v":
pass
- elif arg == "-av":
+ elif mode == "-av":
pass
-from pytubefix import YouTube, Playlist, extract
+from pytubefix import YouTube, Playlist
import requests
import subprocess
import os
return links
-def get_audio_metadata_streams(links):
- audio_streams = []
- metadata = []
-
- for link in links:
- yt = YouTube(link)
- yt.check_availability()
- print(f"Fetching stream for {yt.title}")
- assert len(yt.streams.filter(only_audio=True)) > 0, "No available audio streams"
- audio_streams.append(yt.streams.filter(only_audio=True).order_by("abr").last())
- metadata.append(
- {
- "title": yt.title,
- "artist": yt.author,
- "thumbnail_url": yt.thumbnail_url,
- "publish_date": yt.publish_date,
- "views": yt.views
- }
- )
- return audio_streams, metadata
+def get_audio_metadata_stream(link):
+ yt = YouTube(link)
+ yt.check_availability()
+ print(f"Fetching stream for {yt.title}")
+ assert len(yt.streams.filter(only_audio=True)) > 0, "No available audio streams"
+ yield yt.streams.filter(only_audio=True).order_by("abr").last()
+ yield {
+ "title": yt.title,
+ "artist": yt.author,
+ "thumbnail_url": yt.thumbnail_url,
+ "publish_date": yt.publish_date,
+ "views": yt.views
+ }
def big_num_format(num): # https://stackoverflow.com/a/579376
magnitude = 0
return '%.1f%s' % (num, ['', 'K', 'M', 'B'][magnitude])
-def download_audio_streams(audio_streams, metadata):
- for audio_stream, md in zip(audio_streams, metadata):
- print(f"Downloading audio stream for {audio_stream.title}")
- audio_stream.download()
- data = requests.get(md["thumbnail_url"]).content
- f = open('thumbnail.jpg', 'wb')
+def download_audio_stream(audio_stream, metadata):
+ print(f"Downloading audio stream for {audio_stream.title}")
+ audio_stream.download()
+
+ # create thumbnail file
+ data = requests.get(metadata["thumbnail_url"]).content
+ thumbnail_filename = f'{audio_stream.title}.jpg'
+ with open(thumbnail_filename, 'wb') as f:
f.write(data)
- f.close()
- command = [
- 'ffmpeg',
- '-i', audio_stream.default_filename,
- '-i', "thumbnail.jpg",
- '-map', '0',
- '-map', '1',
- '-metadata', f'title={audio_stream.title}',
- '-metadata', f'artist={md["artist"]}',
- '-metadata', f'date={md["publish_date"]}',
- '-metadata', f'comment={big_num_format(md["views"]) + " views"}',
- audio_stream.title + ".mp4",
- '-y'
- ]
+ command = [
+ 'ffmpeg',
+ '-i', audio_stream.default_filename,
+ '-i', thumbnail_filename,
+ '-map', '0',
+ '-map', '1',
+ '-metadata', f'title={audio_stream.title}',
+ '-metadata', f'artist={metadata["artist"]}',
+ '-metadata', f'date={metadata["publish_date"]}',
+ '-metadata', f'comment={big_num_format(metadata["views"]) + " views"}',
+ audio_stream.title + ".mp4",
+ '-y'
+ ]
+ subprocess.run(command)
- subprocess.run(command)
- os.remove("thumbnail.jpg")
- os.remove(audio_stream.default_filename)
+ # clean up tmp files
+ os.remove(thumbnail_filename)
+ os.remove(audio_stream.default_filename)