Download video in mp3 format using pytube - python-3.x

I have been using pytube to download youtube videos in python. So far I have been able to download in mp4 format.
yt = pytube.YouTube("https://www.youtube.com/watch?v=WH7xsW5Os10")
vids= yt.streams.all()
for i in range(len(vids)):
print(i,'. ',vids[i])
vnum = int(input("Enter vid num: "))
vids[vnum].download(r"C:\YTDownloads")
print('done')
I managed to download the 'audio' version, but it was in .mp4 format. I did try to rename the extension to .mp3, and the audio played, but the application (Windows Media Player) stopped responding and it began to lag.
How can I download the video as an audio file, in .mp3 format directly? Please provide some code as I am new to working with this module.

How can I download the video as an audio file, in .mp3 format directly?
I'm afraid you can't. The only files available for direct download are the ones which are listed under yt.streams.all().
However, it is straightforward to convert the downloaded audio file from .mp4 to .mp3 format. For example, if you have ffmpeg installed, running this command from the terminal will do the trick (assuming you're in the download directory):
$ ffmpeg -i downloaded_filename.mp4 new_filename.mp3
Alternatively, you can use Python's subprocess module to execute the ffmpeg command programmatically:
import os
import subprocess
import pytube
yt = pytube.YouTube("https://www.youtube.com/watch?v=WH7xsW5Os10")
vids= yt.streams.all()
for i in range(len(vids)):
print(i,'. ',vids[i])
vnum = int(input("Enter vid num: "))
parent_dir = r"C:\YTDownloads"
vids[vnum].download(parent_dir)
new_filename = input("Enter filename (including extension): ")) # e.g. new_filename.mp3
default_filename = vids[vnum].default_filename # get default name using pytube API
subprocess.run([
'ffmpeg',
'-i', os.path.join(parent_dir, default_filename),
os.path.join(parent_dir, new_filename)
])
print('done')
EDIT: Removed mention of subprocess.call. Use subprocess.run (unless you're using Python 3.4 or below)

I am assuming you are using Python 3 and pytube 9.x, you can use the filter method to "filter", the file extension you are interested in.
For example, if you would like to download mp4 video file format it would look like the following:
pytube.YouTube("url here").streams.filter(file_extension="mp4").first()
if you would like to pull audio it would look like the following:
pytube.YouTube("url here").streams.filter(only_audio=True).all()
Hope that helps anyone landing on this page; rather than converting unnecessarily.

You will need to install pytubemp3 (using pip install pytubemp3) latest version 0.3 + then
from pytubemp3 import YouTube
YouTube(video_url).streams.filter(only_audio=True).first().download()

Pytube does not support "mp3" format but you can download audio in webm format. The following code demonstrates it.
from pytube import YouTube
yt = YouTube("https://www.youtube.com/watch?v=kn8ZuOCn6r0")
stream = yt.streams.get_by_itag(251)
the itag is unique id to get file with sppecific resolution
stream.download()
For mp3 you have to convert (mp4 or webm) file format to mp3.

With this code you will download all the videos from a playlist and saving them with the title from youtube in mp4 and mp4 audio formats.
i used the code from #scrpy in this question and the hint from #Jean-Pierre Schnyder
from this answer
import os
import subprocess
import re
from pytube import YouTube
from pytube import Playlist
path =r'DESTINATION_FOLER'
playlist_url = 'PLAYLIST_URL'
play = Playlist(playlist_url)
play._video_regex = re.compile(r"\"url\":\"(/watch\?v=[\w-]*)")
print(len(play.video_urls))
for url in play.video_urls:
yt = YouTube(url)
audio = yt.streams.get_audio_only()
audio.download(path)
nome = yt.title
new_filename=nome+'.mp3'
default_filename =nome+'.mp4'
ffmpeg = ('ffmpeg -i ' % path default_filename + new_filename)
subprocess.run(ffmpeg, shell=True)
print('Download Complete')

Download the video as audio, then just change the audio extension to MP3:
from pytube import YouTube
import os
url = str(input("url:- "))
yt = YouTube(url)
video = yt.streams.filter(only_audio=True).first()
downloaded_file = video.download()
base, ext = os.path.splitext(downloaded_file)
new_file = base + '.mp3'
os.rename(downloaded_file, new_file)
print("Done")

here is a mildly more slim and dense format for downloading an mp4 video and converting from mp4 to mp3:
Download will download the file to the current directory or location of the program, this will also convert the file to mp3 as a NEW file.
from pytube import YouTube
import os
import subprocess
import time
while True:
url = input("URL: ")
# Title and Time
print("...")
print(((YouTube(url)).title), "//", (int(var1)/60),"mins")
print("...")
# Filename specification
# Prevents any errors during conversion due to illegal characters in name
_filename = input("Filename: ")
# Downloading
print("Downloading....")
YouTube(url).streams.first().download(filename=_filename)
time.sleep(1)
# Converting
mp4 = "'%s'.mp4" % _filename
mp3 = "'%s'.mp3" % _filename
ffmpeg = ('ffmpeg -i %s ' % mp4 + mp3)
subprocess.call(ffmpeg, shell=True)
# Completion
print("\nCOMPLETE\n")
This is an infinite loop that will allow the renaming, download, and conversion of multiple URLs.

from pytube import YouTube
yt = YouTube(url)
yt.streams.get_audio_only().download(output_path='/home/',filename=yt.title)

Pytube does not support "mp3" format but you can download audio in webm format. The following code demonstrates it.
from pytube import YouTube
yt = YouTube("https://www.youtube.com/watch?v=kn8ZuOCn6r0")
stream = yt.streams.get_by_itag(251)
stream.download()
For mp3 you have to convert (mp4 or webm) file format to mp3.

This is my solution:
import os
import sys
from pytube import YouTube
from pytube.cli import on_progress
PATH_SAVE = "D:\Downloads"
yt = YouTube("YOUR_URL", on_progress_callback=on_progress)
#Download mp3
audio_file = yt.streams.filter(only_audio=True).first().download(PATH_SAVE)
base, ext = os.path.splitext(audio_file)
new_file = base + '.mp3'
os.rename(audio_file, new_file)
#Download Video
ys = yt.streams.filter(res="1080p").first()
ys.download(PATH_SAVE)
Working: Python v3.9.x and pytube v11.0.1

try to use :
from pytube import YouTube
import os
link = input('enter the link: ')
path = "D:\\" #enter the path where you want to save your video
video = YouTube(link)
print( "title is : ", video.title)
#download video
print("title is : ", video.title)
video.streams.filter(only_audio=True).first().download( path , filename ="TemporaryName.Mp4" )
#remove caracters (" | , / \ ..... ) from video title
VideoTitle = video.title
VideoTitle = VideoTitle.replace('\"' , " ")
VideoTitle = VideoTitle.replace('|', " ")
VideoTitle = VideoTitle.replace(',', " ")
VideoTitle = VideoTitle.replace('/"' , " ")
VideoTitle = VideoTitle.replace('\\', " ")
VideoTitle = VideoTitle.replace(':', " ")
VideoTitle = VideoTitle.replace('*"' , " ")
VideoTitle = VideoTitle.replace('?', " ")
VideoTitle = VideoTitle.replace('<', " ")
VideoTitle = VideoTitle.replace('>"' , " ")
#change name and converting Mp4 to Mp3
my_file = path + "\\" + "TemporaryName.mp4"
base = path + "\\" + VideoTitle
print("New Video Title is :" +VideoTitle)
os.rename(my_file, base + '.mp3')
print(video.title, ' \nhas been successfully downloaded as MP3')

This is my solution:
from os import path, rename
from pytube import YouTube as yt
formato = ""
descarga = desktop = path.expanduser("~/Desktop")
link = input("Inserte el enlace del video: ")
youtube = yt(link)
while formato != "mp3" and formato != "mp4":
formato = input("¿Será en formato mp3 o mp4? ")
if formato == "mp4":
youtube.streams.get_highest_resolution().download(descarga)
elif formato == "mp3":
video = youtube.streams.first()
downloaded_file = video.download(descarga)
base, ext = path.splitext(downloaded_file)
new_file = base + '.mp3'
rename(downloaded_file, new_file)
print("Descarga completa!")
input("Presiona Enter para salir...")

Here is my solution. Just rename downloaded content's name with pytube's filename option.
url = input("URL of the video that will be downloaded as MP^: ")
try:
video = yt(url)
baslik = video.title
print(f"Title: {baslik}")
loc = input("Location: ")
print(f"Getting ITAG info for {baslik}")
for itag in video.streams.filter(only_audio=True): # It'll show only audio streams.
print(itag)
itag = input("ITAG secimi: ")
print(f"{baslik} sesi {loc} konumuna indiriliyor.")
video.streams.get_by_itag(itag).download(loc, filename=baslik + ".mp3") # And you can rename video by filename= option. Just add .mp3 extension to video's title.
print("Download finished.")
except:
print("Enter a valid URL")
sys.exit()

This worked very well for me:
pip install pytube
pip install os_sys
# importing packages
from pytube import YouTube
import os
# url input from user
yt = YouTube(
str(input("paste your link")))
# extract only audio
video = yt.streams.filter(only_audio=True).first()
# check for destination to save file
print("Enter the destination (leave blank for current directory)")
destination = str(input(">> ")) or '.'
# download the file
out_file = video.download(output_path=destination)
# save the file
base, ext = os.path.splitext(out_file)
new_file = base + '.mp3'
os.rename(out_file, new_file)
# result of success
print(yt.title + " has been successfully downloaded.")

Here is the function that downloads music in the highest available quality using pytube and saves it in desired directory.
from pytube import YouTube
import os
from pathlib import Path
def youtube2mp3 (url,outdir):
# url input from user
yt = YouTube(url)
### Extract audio with 160kbps quality from video
video = yt.streams.filter(abr='160kbps').last()
### Downloadthe file
out_file = video.download(output_path=outdir)
base, ext = os.path.splitext(out_file)
new_file = Path(f'{base}.mp3')
os.rename(out_file, new_file)
### Check success of download
if new_file.exists():
print(f'{yt.title} has been successfully downloaded.')
else:
print(f'ERROR: {yt.title}could not be downloaded!')

I have a more Pythonic way to download YouTube videos as MP3 using PyTube:
# Use PyTube to download a YouTube video, then convert to MP3 (if needed) using MoviePy
import pytube
from moviepy.editor import AudioFileClip
link = "your youtube link here"
fn = "myfilename.mp3"
yt = pytube.YouTube(str(link))
video = yt.streams.filter(only_audio=True).first()
out_file = video.download(output_path='.')
os.rename(out_file, fn)
# Check is the file a MP3 file or not
if not out_file.endswith('.mp3'):
# File is not a MP3 file, then try to convert it (first rename it)
dlfn = '.'.join(fn.split('.')[:-1]) + '.' + out_file.split('.')[-1]
os.rename(fn, dlfn)
f = AudioFileClip(dlfn)
f.write_audiofile(fn)
f.close()
os.remove(dlfn)
Code is written in Python3.
Be sure to install the libraries:
python3 -m pip install pytube moviepy
MoviePy dont support every audio files, but it support the most of ones: "empty" mp4 (mp4 that only have music), wav, etc...
Why conversion to MP3 is important ?
A lot of persons just renames the file, but this cannot convert a file ! If you use VLC by example, VLC will play the file not as an MP3, but as the original format. So, if you play the file with a software that only support MP3, the audio player will return an error.

Related

No sound in video downloaded from youtube using pytube

I'm able to download the video using "pytube" library but, the downloaded video has no sound in playback!
Here's what I've tried...
"""
Developer: #skywalkerSam
Aim: To download youtube videos...
Date: 12022.07.13.03:00
"""
from pytube import YouTube
yt = YouTube("https://www.youtube.com/watch?v=kJQP7kiw5Fk", use_oauth=True, allow_oauth_cache=True)
def info():
print("\nTitle: ", yt.title)
print("Views: ", yt.views)
# print("Description: \t", yt.description)
print("Thumbnail: ", yt.thumbnail_url)
print('Stream Options: \n', yt.streams.filter().order_by('resolution').desc(), '\n')
def download():
yt.streams.filter(progressive=True)
stream = yt.streams.get_by_itag(399)
print("\nProcessing Your Request, Please Wait...\n")
stream.download(output_path="C:\\Users\\samsk\\Downloads\\Youtube\\")
print("\nDownload Complete :) \n")
if __name__ == "__main__":
try:
info()
download()
except KeyboardInterrupt:
print("\n\n Operation Cancelled By User :( \n")
exit()
except Exception as e:
print("\nError: ", e)
Please help me with this, Thank You...
You must download the audio and video to combine the two
I did it with moviepy:
import moviepy.editor as mpe
vname = "clip.mp4"
aname = "audio.mp3"
# Download video and rename
video = pytube.YouTube(url).streams.filter(subtype='mp4', res="1080p").first().download()
os.rename(video, vname)
# Download audio and rename
audio = pytube.YouTube(url).streams.filter(only_audio=True).first().download()
os.rename(audio, aname)
# Setting the audio to the video
video = mpe.VideoFileClip(vname)
audio = mpe.AudioFileClip(aname)
final = video.set_audio(audio)
# Output result
final.write_videofile("video.mp4")
# Delete video and audio to keep the result
os.remove(vname)
os.remove(aname)
Here's a working script to download videos from youtube, install required modules on your system, and change youtube URLs (if you want) and You're good to go
import moviepy.editor as mpe
import os
import pytube
vname = "clip.mp4"
aname = "audio.mp3"
# Download video and rename
video = pytube.YouTube("https://www.youtube.com/watch?v=kJQP7kiw5Fk").streams.filter(
subtype='mp4', res="1080p").first().download()
os.rename(video, vname)
# Download audio and rename
audio = pytube.YouTube(
"https://www.youtube.com/watch?v=kJQP7kiw5Fk").streams.filter(only_audio=True).first().download()
os.rename(audio, aname)
# Setting the audio to the video
video = mpe.VideoFileClip(vname)
audio = mpe.AudioFileClip(aname)
final = video.set_audio(audio)
# Output result
final.write_videofile("video.mp4")
# Delete video and audio to keep the result
os.remove(vname)
os.remove(aname)
Takes a bit of time to compile audio & video together. So, give it some time...

cv2 wait key (Hoping to make it variable depending on latency)

When using my code bellow (It turns YouTube videos into ASCII with audio) The latency between the audio and video grows bigger each frame (I have tried many different wait times) I was wondering if there is a way to change the code to make it so the wait key changes depending on how much latency there is. I have only been coding for 6 months so sorry if there is any bad code.
import pytube
import os
import cv2
import PIL.Image
import winsound
from moviepy.editor import *
from pydub import AudioSegment
import threading
import time
##################################################
# downloads the youtube video and lets you input the path for where it should be saved
url = input ("Enter the you youtube url: \n\n")
path = input ("Enter the path where you want the youtube video to be saved: \n\n")
try:
youtube = pytube.YouTube(url)
streams = youtube.streams.all()
video = youtube.streams.get_highest_resolution()
video.download(path)
print ("Done!")
except:
print ("\nYoutube video has coppy righted material so it can not be downloaded. Try again with a different video")
##################################################
#locates all the files with the file extension .mp4
for root, dirs, files in os.walk(path):
for file in files:
if file.endswith(".mp4"):
file_name = (file)
file_path = (os.path.join(root,file))
print (file_name)
print (file_path)
##################################################
mp3_file = (path+"\\")
mp3_file = (mp3_file+"audio.mp3")
mp4_file = (path+"\\")
mp4_file = (mp4_file+file_name)
VideoClip = VideoFileClip(mp4_file)
audioclip = VideoClip.audio
audioclip.write_audiofile(mp3_file)
audioclip.close()
VideoClip.close()
sound = AudioSegment.from_mp3(mp3_file)
sound.export(path+"/audio.wav", format = "wav")
##################################################
def a():
# Ascii characters used to create the output
ASCII_CHARS = ["#", "#", "S", "%", "?", "*", "+", ";", ":", ",", "."]
def resized_gray_image(image ,new_width=80):
width,height = image.size
aspect_ratio = height/width
new_height = int(aspect_ratio * new_width)
resized_gray_image = image.resize((new_width,new_height)).convert('L')
return resized_gray_image
def pix2chars(image):
pixels = image.getdata()
characters = "".join([ASCII_CHARS[pixel//25] for pixel in pixels])
return characters
def generate_frame(image,new_width=80):
new_image_data = pix2chars(resized_gray_image(image))
total_pixels = len(new_image_data)
ascii_image = "\n".join([new_image_data[index:(index+new_width)] for index in range(0, total_pixels, new_width)])
sys.stdout.write(ascii_image)
os.system('cls' if os.name == 'nt' else 'clear')
cap = cv2.VideoCapture(mp4_file)
print (cap)
try:
while True:
ret,frame = cap.read()
cv2.imshow("frame",frame)
generate_frame(PIL.Image.fromarray(frame))
cv2.waitKey(1)
except:
threading.Thread(target=c).start()
##################################################
def b():
winsound.PlaySound(path+"/audio.wav",winsound.SND_FILENAME)
##################################################
def c ():
os.remove (mp3_file)
os.remove (mp4_file)
os.remove (path+"/audio.wav")
threading.Thread(target=a).start()
threading.Thread(target=b).start()

Find time length of mp3 - python

Here is my code:
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
from pydub import AudioSegment
import os
from urllib.parse import urlparse, parse_qs, unquote
from pytube import YouTube# misc
import urllib.request
from moviepy.editor import *
import eyed3
import time
class ConvertToMp3:
def convert(self,filename):
path_list = filename.split("/")
filename = path_list[len(path_list)-1]
path_list.remove(filename)
if(len(path_list)!=0 and path_list[0]==""):
path_list.remove(path_list[0])
path = ""
for folder in path_list:
path = path+"/"+folder
extension = filename.split(".")[1]
if path!="":
audio = AudioSegment.from_file(path+"/"+filename, format=extension)
else:
audio = AudioSegment.from_file(filename, format=extension)
audio.export("output files/"+filename.split(".")[0]+".mp3", format="mp3")
class ConvertFromYoutube:
def download(self,video_url,**options):
video_id = parse_qs(urlparse(video_url).query)['v'][0]
video = YouTube('https://www.youtube.com/watch?v='+video_id)
video.streams.get_by_itag(18).download("output files")
title = video.title
#print(title)
thumbnail = video.thumbnail_url
thumbnail_extension = thumbnail.split(".")
thumbnail_extension = thumbnail_extension[len(thumbnail_extension)-1]
urllib.request.urlretrieve(thumbnail, "output files/"+title+"."+thumbnail_extension)
self.save_as_mp3(title,"song_artist","song_album","song_album_artist","*****")
def save_as_mp3(self,song_title,song_artist,song_album,song_album_artist,song_rating):
video = VideoFileClip(os.path.join("output files",song_title+".mp4"))
video.audio.write_audiofile(os.path.join("output files",song_title+".mp3"))
audiofile = eyed3.load(os.path.join("output files",song_title+".mp3"))
audiofile.tag.artist = song_artist
audiofile.tag.album = song_album
audiofile.tag.album_artist = song_album_artist
audiofile.tag.title = song_title
print(audiofile.info.time_secs)
audiofile_duration = time.strftime('%H:%M:%S', time.gmtime(audiofile.info.time_secs))
print(audiofile.info.time_secs)
print(audiofile_duration)
audiofile.tag.save()
#test
#converter = ConvertToMp3()
#converter.convert("/home/chris/Μουσική/Απολυτίκιο Τριών Ιεραρχών.wav")
youtube = ConvertFromYoutube()
youtube.download("https://www.youtube.com/watch?v=JuYeHPFR3f0")
The time of pokemon theme song youtube video is: 3 minutes and 21 seconds.
The same information from file properties:
But print(audiofile.info.time_secs)
Prints out 405.62361067503923. That's wrong, so the calculation audiofile_duration = time.strftime('%H:%M:%S', time.gmtime(audiofile.info.time_secs)) is also wrong.
How can i fix that?
Thanks in advance,
Chris Pappas
Edit:
object_methods = [attr for attr in dir(audiofile.info) if not callable(getattr(audiofile.info, attr)) and not attr.startswith("__")]
print(object_methods)
['bit_rate', 'bit_rate_str', 'lame_tag', 'mode', 'mp3_header', 'sample_freq', 'size_bytes', 'time_secs', 'vbri_header', 'xing_header']
I found the solution here:
Finding the length of an mp3 file
But if it not possible to use so many libraries feel free for another answer.

Consume Flask video streaming with ffmpeg

I've created a python Flask video file streamer resource that works well when getting the file in a web browser but is not working when using ffmpeg.
The flask resource is:
from flask_restful import Resource, Api
class Mp4(Resource):
def get(self,grtv,data,canal,arquivo):
path = os.path.abspath('../mp4/' + str(canal) + '/' + str(data) + '/' + str(arquivo))
print(path)
def generate():
with open(path, "rb") as f:
chunk = f.read(1024)
while chunk:
yield chunk
chunk = f.read(1024)
try:
t = os.stat(path)
size = str(t.st_size)
return Response(generate(),mimetype='video/mp4',headers={"Content-Type":"video/mp4","Content-Disposition":"inline","Content-Transfer-Enconding":"binary","Content-Length":size})
except Exception as e:
result = {'result': e}
return result
The ffmpeg command is:
ffmpeg -loglevel debug -i <url> out_teste4.mp4
where url is de address of the streaming video.
The ffmpeg most important output is:
ffmpeg output screenshot 1
ffmpeg output screenshot 2
I've already tried increasing 'analyzeduration' and 'probesize' options.
ffmpeg version: 3.4.2-1~16.04.york0.2.
python version: 3.5.2.
Does anyone can help me to get the video files with ffmpeg? Suggestions can be both on changing the API or the ffmpeg command.
Thank you all!

Convert image sequence to video using Moviepy

I tried to convert PNG images to video by list images in directory
clips[]
for filename in os.listdir('.'):
if filename.endswith(".png"):
clips.append(ImageClip(filename))
Then convert it
video = concatenate(clips, method='compose')
video.write_videofile('test.mp4')
The error is:
Full code
import os
from moviepy.editor import *
clips = []
base_dir = os.path.realpath(".")
print(base_dir)
for filename in os.listdir('.'):
if filename.endswith(".png"):
clips.append(ImageClip(filename))
video = concatenate(clips, method='compose')
video.write_videofile('test.mp4')
I found another way to do it:
from moviepy.editor import *
img = ['1.png', '2.png', '3.png', '4.png', '5.png', '6.png',
'7.png', '8.png', '9.png', '10.png', '11.png', '12.png']
clips = [ImageClip(m).set_duration(2)
for m in img]
concat_clip = concatenate_videoclips(clips, method="compose")
concat_clip.write_videofile("test.mp4", fps=24)
And from current folder:
import os
import glob
from natsort import natsorted
from moviepy.editor import *
base_dir = os.path.realpath("./images")
print(base_dir)
gif_name = 'pic'
fps = 24
file_list = glob.glob('*.png') # Get all the pngs in the current directory
file_list_sorted = natsorted(file_list,reverse=False) # Sort the images
clips = [ImageClip(m).set_duration(2)
for m in file_list_sorted]
concat_clip = concatenate_videoclips(clips, method="compose")
concat_clip.write_videofile("test.mp4", fps=fps)
This is how I did it using your initial code. The error you were seeing was due to not specifying set_duration for the clips. I also sorted the files in the directory so that the resulting mp4 is sequential (was not the case by default).
import os
from moviepy.editor import *
base_dir = os.path.realpath(".")
print(base_dir)
directory=sorted(os.listdir('.'))
print(directory)
for filename in directory:
if filename.endswith(".png"):
clips.append(ImageClip(filename).set_duration(1))
print(clips)
video = concatenate(clips, method="compose")
video.write_videofile('test1.mp4', fps=24)

Resources