Skip to content

Commit

Permalink
Fix: music download api using yt-dlp instead of pytube
Browse files Browse the repository at this point in the history
  • Loading branch information
RafaelJohn9 committed Jul 11, 2024
1 parent abdf9a3 commit 5c86036
Show file tree
Hide file tree
Showing 9 changed files with 225 additions and 29 deletions.
Binary file modified backend/user/api/v1/__pycache__/app.cpython-310.pyc
100755 → 100644
Binary file not shown.
2 changes: 1 addition & 1 deletion backend/user/api/v1/app.py
Original file line number Diff line number Diff line change
Expand Up @@ -89,4 +89,4 @@ def not_found(error):
""" Main Function """
host = getenv('USER_API_HOST', 'localhost')
port = getenv('USER_API_PORT', '5000')
app.run(host=host, port=port, threaded=True)
app.run(host=host, port=port, threaded=True, debug=True)
47 changes: 47 additions & 0 deletions backend/user/api/v1/pdfdrive.log
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
2024-07-11 05:14:52,072 - INFO - Music link for query 'Halo Beyonce': https://www.youtube.com/watch?v=bnVUHWCynig
2024-07-11 05:15:01,385 - ERROR - Exception on /api/v1/user/music/download [POST]
Traceback (most recent call last):
File "/home/johnmkagunda/.local/lib/python3.10/site-packages/pytube/__main__.py", line 181, in fmt_streams
extract.apply_signature(stream_manifest, self.vid_info, self.js)
File "/home/johnmkagunda/.local/lib/python3.10/site-packages/pytube/extract.py", line 409, in apply_signature
cipher = Cipher(js=js)
File "/home/johnmkagunda/.local/lib/python3.10/site-packages/pytube/cipher.py", line 43, in __init__
self.throttling_plan = get_throttling_plan(js)
File "/home/johnmkagunda/.local/lib/python3.10/site-packages/pytube/cipher.py", line 405, in get_throttling_plan
raw_code = get_throttling_function_code(js)
File "/home/johnmkagunda/.local/lib/python3.10/site-packages/pytube/cipher.py", line 311, in get_throttling_function_code
name = re.escape(get_throttling_function_name(js))
File "/home/johnmkagunda/.local/lib/python3.10/site-packages/pytube/cipher.py", line 296, in get_throttling_function_name
raise RegexMatchError(
pytube.exceptions.RegexMatchError: get_throttling_function_name: could not find match for multiple

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
File "/home/johnmkagunda/.local/lib/python3.10/site-packages/flask/app.py", line 1473, in wsgi_app
response = self.full_dispatch_request()
File "/home/johnmkagunda/.local/lib/python3.10/site-packages/flask/app.py", line 882, in full_dispatch_request
rv = self.handle_user_exception(e)
File "/home/johnmkagunda/.local/lib/python3.10/site-packages/flask_cors/extension.py", line 161, in wrapped_function
return cors_after_request(app.make_response(f(*args, **kwargs)))
File "/home/johnmkagunda/.local/lib/python3.10/site-packages/flask/app.py", line 880, in full_dispatch_request
rv = self.dispatch_request()
File "/home/johnmkagunda/.local/lib/python3.10/site-packages/flask/app.py", line 865, in dispatch_request
return self.ensure_sync(self.view_functions[rule.endpoint])(**view_args) # type: ignore[no-any-return]
File "/home/johnmkagunda/repositories/Portfolio-website/backend/user/api/v1/views/recommendations_download.py", line 31, in download_music
audio_stream = yt.streams.filter(only_audio=True).first()
File "/home/johnmkagunda/.local/lib/python3.10/site-packages/pytube/__main__.py", line 296, in streams
return StreamQuery(self.fmt_streams)
File "/home/johnmkagunda/.local/lib/python3.10/site-packages/pytube/__main__.py", line 188, in fmt_streams
extract.apply_signature(stream_manifest, self.vid_info, self.js)
File "/home/johnmkagunda/.local/lib/python3.10/site-packages/pytube/extract.py", line 409, in apply_signature
cipher = Cipher(js=js)
File "/home/johnmkagunda/.local/lib/python3.10/site-packages/pytube/cipher.py", line 43, in __init__
self.throttling_plan = get_throttling_plan(js)
File "/home/johnmkagunda/.local/lib/python3.10/site-packages/pytube/cipher.py", line 405, in get_throttling_plan
raw_code = get_throttling_function_code(js)
File "/home/johnmkagunda/.local/lib/python3.10/site-packages/pytube/cipher.py", line 311, in get_throttling_function_code
name = re.escape(get_throttling_function_name(js))
File "/home/johnmkagunda/.local/lib/python3.10/site-packages/pytube/cipher.py", line 296, in get_throttling_function_name
raise RegexMatchError(
pytube.exceptions.RegexMatchError: get_throttling_function_name: could not find match for multiple
27 changes: 18 additions & 9 deletions backend/user/api/v1/views/recommendations_download.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,12 @@
"""Route for downloading recommendations (movies, music, books)"""
import io
from flask import request, jsonify, send_file, make_response
from pytube import YouTube
import requests
from api.v1.views import app_views
from external_apis.music_downloader.music_link_getter import get_music_link
from external_apis.music_downloader.music_download_link import get_audio_download_link
from external_apis.book_downloader.book_downloader import get_book_download_link


@app_views.route('/music/download', methods=['POST'])
def download_music():
"""Defining route for downloading music"""
Expand All @@ -24,20 +24,29 @@ def download_music():
if not youtube_url:
return jsonify({'error': 'No video found for the given query'}), 404

# Create a YouTube object
yt = YouTube(youtube_url)
# Get the audio download link using get_audio_download_link function
audio_download_link = get_audio_download_link(youtube_url)

# Get the audio-only stream
audio_stream = yt.streams.filter(only_audio=True).first()
if not audio_download_link:
return jsonify({'error': 'Failed to get the audio download link'}), 500

# Create a BytesIO buffer to hold the audio data
audio_file = io.BytesIO()

audio_stream.stream_to_buffer(audio_file)
audio_file.seek(0)
try:
# Download the audio file from the audio_download_link
response = requests.get(audio_download_link)
response.raise_for_status() # Raise an error for bad status codes

# Write the content to the BytesIO buffer
audio_file.write(response.content)
audio_file.seek(0)
except Exception as e:
return jsonify({'error': str(e)}), 500

# Send the audio file as a response
response = make_response(send_file(audio_file, mimetype='audio/mpeg'))
response.headers['Content-Disposition'] = f'attachment; filename={audio_stream.default_filename}'
response.headers['Content-Disposition'] = f'attachment; filename={query}.mp3'

return response

Expand Down
Binary file added backend/user/downloaded_audio.m4a
Binary file not shown.
Original file line number Diff line number Diff line change
@@ -1 +1,5 @@
2024-05-23 22:21:11,716 - ERROR - regex_search: could not find match for (?:v=|\/)([0-9A-Za-z_-]{11}).*
2024-07-11 05:21:36,974 - ERROR - get_throttling_function_name: could not find match for multiple
2024-07-11 05:31:19,587 - ERROR - get_throttling_function_name: could not find match for multiple
2024-07-11 05:40:08,317 - ERROR - ERROR: Postprocessing: ffprobe and ffmpeg not found. Please install or provide the path using --ffmpeg-location
2024-07-11 05:42:52,552 - ERROR - ERROR: [generic] '#!/usr/bin/python3' is not a valid URL. Set --default-search "ytsearch" (or run yt-dlp "ytsearch:#!/usr/bin/python3" ) to search YouTube
47 changes: 28 additions & 19 deletions backend/user/external_apis/music_downloader/music_download_link.py
Original file line number Diff line number Diff line change
@@ -1,33 +1,42 @@
#!/usr/bin/python3
"""Downloads the audio of a YouTube video given its URL."""
"""Provides a direct link to download the audio of a YouTube video given its URL."""
import logging
from pytube import YouTube
import yt_dlp

def music_download_link(url):
"""downloads the audio of a YouTube video given its URL."""
if url == "" or url is None:
def get_audio_download_link(url):
"""Gets the direct download link of the audio of a YouTube video given its URL."""
if not url:
raise ValueError("Invalid URL")
try:
# Create a YouTube object with the given URL
video = YouTube(url)
ydl_opts = {
'format': 'bestaudio/best',
'quiet': True,
'extract_flat': True,
'postprocessors': [{
'key': 'FFmpegExtractAudio',
'preferredcodec': 'mp3',
'preferredquality': '192',
}],
}

# Get the audio stream with the highest bitrate
audio_stream = video.streams.get_audio_only()

# Download the audio stream
audio_stream.download()
# Return the path of the downloaded audio file
return audio_stream.default_filename
# pylint: disable=broad-except
with yt_dlp.YoutubeDL(ydl_opts) as ydl:
info_dict = ydl.extract_info(url, download=False)
audio_url = info_dict['url']
return audio_url
except Exception as e:
# Configure logging
logging.basicConfig(filename='./music_download_link.log',
level=logging.ERROR,
format='%(asctime)s - %(levelname)s - %(message)s')
level=logging.ERROR,
format='%(asctime)s - %(levelname)s - %(message)s')

# Log the error
logging.error(str(e))
return None

if __name__=="__main__":
if __name__ == "__main__":
download_url = input("Enter the URL of the YouTube video: ")
music_download_link(download_url)
audio_link = get_audio_download_link(download_url)
if audio_link:
print(f"Direct download link for audio: {audio_link}")
else:
print("Failed to get the download link for the audio.")
126 changes: 126 additions & 0 deletions backend/user/pdfdrive.log
Original file line number Diff line number Diff line change
Expand Up @@ -19,3 +19,129 @@
2024-06-12 16:37:33,194 - INFO - Download completed.
2024-06-12 16:37:33,239 - INFO - Download Link: https://www.pdfdrive.com/download.pdf?id=162146986&h=b75bcf6803e72e63062886dbcd45a676&u=cache&ext=pdf
2024-06-12 16:37:33,307 - INFO - 127.0.0.1 - - [12/Jun/2024 16:37:33] "POST /api/v1/user/book/download HTTP/1.1" 200 -
2024-07-11 05:17:30,604 - INFO - WARNING: This is a development server. Do not use it in a production deployment. Use a production WSGI server instead.
* Running on http://localhost:5000
2024-07-11 05:17:30,645 - INFO - Press CTRL+C to quit
2024-07-11 05:17:44,617 - INFO - WARNING: This is a development server. Do not use it in a production deployment. Use a production WSGI server instead.
* Running on http://localhost:5000
2024-07-11 05:17:44,618 - INFO - Press CTRL+C to quit
2024-07-11 05:17:53,200 - INFO - Music link for query 'Halo Beyonce': https://www.youtube.com/watch?v=bnVUHWCynig
2024-07-11 05:18:03,407 - ERROR - Exception on /api/v1/user/music/download [POST]
Traceback (most recent call last):
File "/home/johnmkagunda/.local/lib/python3.10/site-packages/pytube/__main__.py", line 181, in fmt_streams
extract.apply_signature(stream_manifest, self.vid_info, self.js)
File "/home/johnmkagunda/.local/lib/python3.10/site-packages/pytube/extract.py", line 409, in apply_signature
cipher = Cipher(js=js)
File "/home/johnmkagunda/.local/lib/python3.10/site-packages/pytube/cipher.py", line 43, in __init__
self.throttling_plan = get_throttling_plan(js)
File "/home/johnmkagunda/.local/lib/python3.10/site-packages/pytube/cipher.py", line 405, in get_throttling_plan
raw_code = get_throttling_function_code(js)
File "/home/johnmkagunda/.local/lib/python3.10/site-packages/pytube/cipher.py", line 311, in get_throttling_function_code
name = re.escape(get_throttling_function_name(js))
File "/home/johnmkagunda/.local/lib/python3.10/site-packages/pytube/cipher.py", line 296, in get_throttling_function_name
raise RegexMatchError(
pytube.exceptions.RegexMatchError: get_throttling_function_name: could not find match for multiple

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
File "/home/johnmkagunda/.local/lib/python3.10/site-packages/flask/app.py", line 1473, in wsgi_app
response = self.full_dispatch_request()
File "/home/johnmkagunda/.local/lib/python3.10/site-packages/flask/app.py", line 882, in full_dispatch_request
rv = self.handle_user_exception(e)
File "/home/johnmkagunda/.local/lib/python3.10/site-packages/flask_cors/extension.py", line 161, in wrapped_function
return cors_after_request(app.make_response(f(*args, **kwargs)))
File "/home/johnmkagunda/.local/lib/python3.10/site-packages/flask/app.py", line 880, in full_dispatch_request
rv = self.dispatch_request()
File "/home/johnmkagunda/.local/lib/python3.10/site-packages/flask/app.py", line 865, in dispatch_request
return self.ensure_sync(self.view_functions[rule.endpoint])(**view_args) # type: ignore[no-any-return]
File "/mnt/sdb1/repositories/Portfolio-website/backend/user/api/v1/views/recommendations_download.py", line 31, in download_music
audio_stream = yt.streams.filter(only_audio=True).first()
File "/home/johnmkagunda/.local/lib/python3.10/site-packages/pytube/__main__.py", line 296, in streams
return StreamQuery(self.fmt_streams)
File "/home/johnmkagunda/.local/lib/python3.10/site-packages/pytube/__main__.py", line 188, in fmt_streams
extract.apply_signature(stream_manifest, self.vid_info, self.js)
File "/home/johnmkagunda/.local/lib/python3.10/site-packages/pytube/extract.py", line 409, in apply_signature
cipher = Cipher(js=js)
File "/home/johnmkagunda/.local/lib/python3.10/site-packages/pytube/cipher.py", line 43, in __init__
self.throttling_plan = get_throttling_plan(js)
File "/home/johnmkagunda/.local/lib/python3.10/site-packages/pytube/cipher.py", line 405, in get_throttling_plan
raw_code = get_throttling_function_code(js)
File "/home/johnmkagunda/.local/lib/python3.10/site-packages/pytube/cipher.py", line 311, in get_throttling_function_code
name = re.escape(get_throttling_function_name(js))
File "/home/johnmkagunda/.local/lib/python3.10/site-packages/pytube/cipher.py", line 296, in get_throttling_function_name
raise RegexMatchError(
pytube.exceptions.RegexMatchError: get_throttling_function_name: could not find match for multiple
2024-07-11 05:18:03,413 - INFO - 127.0.0.1 - - [11/Jul/2024 05:18:03] "POST /api/v1/user/music/download HTTP/1.1" 500 -
2024-07-11 05:18:51,693 - INFO - WARNING: This is a development server. Do not use it in a production deployment. Use a production WSGI server instead.
* Running on http://localhost:5000
2024-07-11 05:18:51,694 - INFO - Press CTRL+C to quit
2024-07-11 05:18:51,695 - INFO - * Restarting with stat
2024-07-11 05:18:53,796 - WARNING - * Debugger is active!
2024-07-11 05:18:54,021 - INFO - * Debugger PIN: 395-314-336
2024-07-11 05:18:56,850 - INFO - Music link for query 'Halo Beyonce': https://www.youtube.com/watch?v=bnVUHWCynig
2024-07-11 05:19:06,984 - INFO - 127.0.0.1 - - [11/Jul/2024 05:19:06] "POST /api/v1/user/music/download HTTP/1.1" 500 -
2024-07-11 05:30:18,427 - INFO - * Detected change in '/home/johnmkagunda/.local/lib/python3.10/site-packages/pip/_vendor/cachecontrol/__init__.py', reloading
2024-07-11 05:30:18,691 - INFO - * Restarting with stat
2024-07-11 05:30:19,853 - WARNING - * Debugger is active!
2024-07-11 05:30:19,854 - INFO - * Debugger PIN: 395-314-336
2024-07-11 05:32:18,946 - INFO - WARNING: This is a development server. Do not use it in a production deployment. Use a production WSGI server instead.
* Running on http://localhost:5000
2024-07-11 05:32:18,946 - INFO - Press CTRL+C to quit
2024-07-11 05:32:18,947 - INFO - * Restarting with stat
2024-07-11 05:32:20,164 - WARNING - * Debugger is active!
2024-07-11 05:32:20,165 - INFO - * Debugger PIN: 395-314-336
2024-07-11 05:32:48,584 - INFO - Music link for query 'Halo Beyonce': https://www.youtube.com/watch?v=bnVUHWCynig
2024-07-11 05:33:05,905 - INFO - 127.0.0.1 - - [11/Jul/2024 05:33:05] "POST /api/v1/user/music/download HTTP/1.1" 500 -
2024-07-11 05:38:27,495 - INFO - * Detected change in '/mnt/sdb1/repositories/Portfolio-website/backend/user/external_apis/music_downloader/music_download_link.py', reloading
2024-07-11 05:38:28,021 - INFO - * Restarting with stat
2024-07-11 05:38:30,983 - WARNING - * Debugger is active!
2024-07-11 05:38:30,987 - INFO - * Debugger PIN: 395-314-336
2024-07-11 05:38:47,835 - INFO - WARNING: This is a development server. Do not use it in a production deployment. Use a production WSGI server instead.
* Running on http://localhost:5000
2024-07-11 05:38:47,835 - INFO - Press CTRL+C to quit
2024-07-11 05:38:47,836 - INFO - * Restarting with stat
2024-07-11 05:38:48,831 - WARNING - * Debugger is active!
2024-07-11 05:38:48,832 - INFO - * Debugger PIN: 395-314-336
2024-07-11 05:39:09,767 - INFO - Music link for query 'Halo Beyonce': https://www.youtube.com/watch?v=bnVUHWCynig
2024-07-11 05:39:20,003 - INFO - 127.0.0.1 - - [11/Jul/2024 05:39:20] "POST /api/v1/user/music/download HTTP/1.1" 500 -
2024-07-11 05:42:42,309 - INFO - * Detected change in '/mnt/sdb1/repositories/Portfolio-website/backend/user/external_apis/music_downloader/music_download_link.py', reloading
2024-07-11 05:42:44,105 - INFO - * Restarting with stat
2024-07-11 05:43:31,881 - INFO - WARNING: This is a development server. Do not use it in a production deployment. Use a production WSGI server instead.
* Running on http://localhost:5000
2024-07-11 05:43:31,881 - INFO - Press CTRL+C to quit
2024-07-11 05:43:31,882 - INFO - * Restarting with stat
2024-07-11 05:43:32,921 - WARNING - * Debugger is active!
2024-07-11 05:43:32,921 - INFO - * Debugger PIN: 395-314-336
2024-07-11 05:43:38,575 - INFO - Music link for query 'Halo Beyonce': https://www.youtube.com/watch?v=bnVUHWCynig
2024-07-11 05:43:48,855 - INFO - 127.0.0.1 - - [11/Jul/2024 05:43:48] "POST /api/v1/user/music/download HTTP/1.1" 500 -
2024-07-11 05:44:07,476 - INFO - WARNING: This is a development server. Do not use it in a production deployment. Use a production WSGI server instead.
* Running on http://localhost:5000
2024-07-11 05:44:07,477 - INFO - Press CTRL+C to quit
2024-07-11 05:44:07,478 - INFO - * Restarting with stat
2024-07-11 05:44:08,418 - WARNING - * Debugger is active!
2024-07-11 05:44:08,419 - INFO - * Debugger PIN: 395-314-336
2024-07-11 05:44:10,836 - INFO - Music link for query 'Halo Beyonce': https://www.youtube.com/watch?v=bnVUHWCynig
2024-07-11 05:44:20,939 - INFO - 127.0.0.1 - - [11/Jul/2024 05:44:20] "POST /api/v1/user/music/download HTTP/1.1" 500 -
2024-07-11 05:47:18,756 - INFO - WARNING: This is a development server. Do not use it in a production deployment. Use a production WSGI server instead.
* Running on http://localhost:5000
2024-07-11 05:47:18,757 - INFO - Press CTRL+C to quit
2024-07-11 05:47:18,760 - INFO - * Restarting with stat
2024-07-11 05:47:20,565 - WARNING - * Debugger is active!
2024-07-11 05:47:20,565 - INFO - * Debugger PIN: 395-314-336
2024-07-11 05:47:21,749 - INFO - Music link for query 'Halo Beyonce': https://www.youtube.com/watch?v=bnVUHWCynig
2024-07-11 05:47:29,179 - INFO - 127.0.0.1 - - [11/Jul/2024 05:47:29] "POST /api/v1/user/music/download HTTP/1.1" 500 -
2024-07-11 06:52:57,959 - INFO - * Detected change in '/mnt/sdb1/repositories/Portfolio-website/backend/user/api/v1/views/recommendations_download.py', reloading
2024-07-11 06:52:58,864 - INFO - * Restarting with stat
2024-07-11 06:53:05,621 - WARNING - * Debugger is active!
2024-07-11 06:53:05,624 - INFO - * Debugger PIN: 395-314-336
2024-07-11 06:53:49,513 - INFO - WARNING: This is a development server. Do not use it in a production deployment. Use a production WSGI server instead.
* Running on http://localhost:5000
2024-07-11 06:53:49,515 - INFO - Press CTRL+C to quit
2024-07-11 06:53:49,521 - INFO - * Restarting with stat
2024-07-11 06:53:57,611 - WARNING - * Debugger is active!
2024-07-11 06:53:57,613 - INFO - * Debugger PIN: 395-314-336
2024-07-11 06:53:59,839 - INFO - Music link for query 'Halo Beyonce': https://www.youtube.com/watch?v=bnVUHWCynig
2024-07-11 06:56:00,497 - INFO - 127.0.0.1 - - [11/Jul/2024 06:56:00] "POST /api/v1/user/music/download HTTP/1.1" 200 -
2024-07-11 06:56:14,520 - INFO - Music link for query 'Halo Beyonce': https://www.youtube.com/watch?v=bnVUHWCynig
2024-07-11 06:58:12,374 - INFO - 127.0.0.1 - - [11/Jul/2024 06:58:12] "POST /api/v1/user/music/download HTTP/1.1" 200 -
1 change: 1 addition & 0 deletions backend/user/requirements.txt
Original file line number Diff line number Diff line change
Expand Up @@ -17,3 +17,4 @@ python-dotenv>=1.0.1
bs4>=0.0.1
selenium>=4.19.0
webdriver-manager>=4.0.1
yt-dlp>=2024.4.9

0 comments on commit 5c86036

Please sign in to comment.