Improved conversion with ffmpeg (#60)

* Conversion with ffmpeg is more flexible now

* Testing OK after introducing changes

* Normalized genre and disc number across functions

* Small indentation problems

* Remove if condition for setting log level to error
This commit is contained in:
Robert J
2017-06-04 02:26:59 +07:00
committed by Ritiek Malhotra
parent 91947bca74
commit 84d0fb7379

167
spotdl.py
View File

@@ -9,13 +9,12 @@ from slugify import slugify
from titlecase import titlecase from titlecase import titlecase
from mutagen.mp4 import MP4, MP4Cover from mutagen.mp4 import MP4, MP4Cover
import spotipy import spotipy
import spotipy.oauth2 as oauth2
import eyed3 import eyed3
import requests import requests
import pafy import pafy
import os import os
import argparse import argparse
import pathlib
import spotipy.oauth2 as oauth2
def getInputLink(links): def getInputLink(links):
@@ -35,8 +34,7 @@ def getInputLink(links):
def isSpotify(raw_song): def isSpotify(raw_song):
if (len(raw_song) == 22 and raw_song.replace(" ", "%20") if (len(raw_song) == 22 and raw_song.replace(" ", "%20") == raw_song) or (raw_song.find('spotify') > -1):
== raw_song) or (raw_song.find('spotify') > -1):
return True return True
else: else:
return False return False
@@ -124,14 +122,14 @@ def generateFileName(content):
def downloadSong(content): def downloadSong(content):
music_file = generateFileName(content) music_file = generateFileName(content)
if args.input_ext == '.webm': if input_ext == '.webm':
link = content.getbestaudio(preftype='webm') link = content.getbestaudio(preftype='webm')
if link is not None: if link is not None:
link.download(filepath='Music/' + music_file + args.input_ext) link.download(filepath='Music/' + music_file + input_ext)
else: else:
link = content.getbestaudio(preftype="m4a") link = content.getbestaudio(preftype="m4a")
if link is not None: if link is not None:
link.download(filepath="Music/" + music_file + ".m4a") link.download(filepath='Music/' + music_file + input_ext)
def convertToMP3(music_file): def convertToMP3(music_file):
@@ -156,32 +154,59 @@ def convertToMP3(music_file):
os.remove('Music/' + music_file + '.m4a') os.remove('Music/' + music_file + '.m4a')
def convertToM4A(music_file): def convertWithFfmpeg(music_file):
# Here we prefer downloading .webm (Opus) audio and encode as m4a # What are the differences and similarities between ffmpeg, libav, and avconv?
# in format prefered by iTunes - AAC (256k) # https://stackoverflow.com/questions/9477115
# We are using ffmpeg with fdk_aac code and cutoff at 18kHz # ffmeg encoders high to lower quality
# python3 spotdl.py -i '.webm' -o '.m4a' # libopus > libvorbis >= libfdk_aac > aac > libmp3lame
# libfdk_aac due to copyrights needs to be compiled by end user
# on MacOS brew install ffmpeg --with-fdk-aac will do just that. Other OS?
# https://trac.ffmpeg.org/wiki/Encode/AAC
#
if args.quiet: if args.quiet:
ffmpeg_pre = 'ffmpeg -hide_banner -nostats -v panic -y ' ffmpeg_pre = 'ffmpeg -hide_banner -nostats -v panic -y '
else: else:
ffmpeg_pre = 'ffmpeg -y ' ffmpeg_pre = 'ffmpeg -y '
os.system(ffmpeg_pre +
'-i "Music/' + music_file + args.input_ext + '" ' +
'-cutoff 18000 -c:a libfdk_aac -b:a 256k -vn ' +
'"Music/_' + music_file + args.output_ext + '" ')
os.remove('Music/' + music_file + args.input_ext) if input_ext == '.m4a':
if output_ext == '.mp3':
ffmpeg_params = '-codec:v copy -codec:a libmp3lame -q:a 2 '
elif output_ext == '.webm':
ffmpeg_params = '-c:a libopus -vbr on -b:a 192k -vn '
else:
return
elif input_ext == '.webm':
if output_ext == '.mp3':
ffmpeg_params = '-ab 192k -ar 44100 -vn '
elif output_ext == '.m4a':
ffmpeg_params = '-cutoff 20000 -c:a libfdk_aac -b:a 256k -vn '
else:
return
else:
print('Unknown formats. Unable to convert.', input_ext, output_ext)
return
if not args.quiet:
print(ffmpeg_pre +
'-i "Music/' + music_file + input_ext + '" ' +
ffmpeg_params +
'"Music/' + music_file + output_ext + '" ')
os.system(
ffmpeg_pre +
'-i "Music/' + music_file + input_ext + '" ' +
ffmpeg_params +
'"Music/' + music_file + output_ext + '" ')
os.remove('Music/' + music_file + input_ext)
def checkExists(music_file, raw_song, islist): def checkExists(music_file, raw_song, islist):
if os.path.exists("Music/" + music_file + ".m4a.temp"): if os.path.exists("Music/" + music_file + input_ext + ".temp"):
os.remove("Music/" + music_file + ".m4a.temp") os.remove("Music/" + music_file + input_ext + ".temp")
if args.no_convert: if args.no_convert:
extension = args.input_ext extension = input_ext
else: else:
if os.path.exists('Music/' + music_file + args.input_ext): extension = output_ext
os.remove('Music/' + music_file + args.input_ext)
extension = args.output_ext
if os.path.isfile("Music/" + music_file + extension): if os.path.isfile("Music/" + music_file + extension):
if extension == '.mp3': if extension == '.mp3':
audiofile = eyed3.load("Music/" + music_file + extension) audiofile = eyed3.load("Music/" + music_file + extension)
@@ -216,6 +241,8 @@ def fixSong(music_file, meta_tags):
audiofile.tag.album_artist = meta_tags['artists'][0]['name'] audiofile.tag.album_artist = meta_tags['artists'][0]['name']
audiofile.tag.album = meta_tags['album']['name'] audiofile.tag.album = meta_tags['album']['name']
audiofile.tag.title = meta_tags['name'] audiofile.tag.title = meta_tags['name']
artist = spotify.artist(meta_tags['artists'][0]['id'])
audiofile.tag.genre = titlecase(artist['genres'][0])
audiofile.tag.track_num = meta_tags['track_number'] audiofile.tag.track_num = meta_tags['track_number']
audiofile.tag.disc_num = meta_tags['disc_number'] audiofile.tag.disc_num = meta_tags['disc_number']
audiofile.tag.release_date = spotify.album( audiofile.tag.release_date = spotify.album(
@@ -248,7 +275,7 @@ def fixSongM4A(music_file, meta_tags):
'disk': 'disk', 'disk': 'disk',
'cpil': 'cpil', 'cpil': 'cpil',
'tempo': 'tmpo'} 'tempo': 'tmpo'}
audiofile = MP4('Music/_' + music_file + args.output_ext) audiofile = MP4('Music/' + music_file + output_ext)
audiofile[tags['artist']] = meta_tags['artists'][0]['name'] audiofile[tags['artist']] = meta_tags['artists'][0]['name']
audiofile[tags['album']] = meta_tags['album']['name'] audiofile[tags['album']] = meta_tags['album']['name']
audiofile[tags['title']] = meta_tags['name'] audiofile[tags['title']] = meta_tags['name']
@@ -257,6 +284,7 @@ def fixSongM4A(music_file, meta_tags):
album = spotify.album(meta_tags['album']['id']) album = spotify.album(meta_tags['album']['id'])
audiofile[tags['year']] = album['release_date'] audiofile[tags['year']] = album['release_date']
audiofile[tags['track']] = [(meta_tags['track_number'], 0)] audiofile[tags['track']] = [(meta_tags['track_number'], 0)]
audiofile[tags['disk']] = [(meta_tags['disc_number'], 0)]
albumart = ( albumart = (
requests.get(meta_tags['album']['images'][0]['url'], stream=True)).raw requests.get(meta_tags['album']['images'][0]['url'], stream=True)).raw
with open('last_albumart.jpg', 'wb') as out_file: with open('last_albumart.jpg', 'wb') as out_file:
@@ -286,16 +314,17 @@ def grabSingle(raw_song, number=None):
downloadSong(content) downloadSong(content)
print('') print('')
if not args.no_convert: if not args.no_convert:
print('Converting ' + music_file + '.m4a to mp3') print('Converting ' + music_file + input_ext + ' to ' + output_ext)
if args.output_ext == '.m4a': if args.ffmpeg:
convertToM4A(music_file) convertWithFfmpeg(music_file)
meta_tags = generateMetaTags(raw_song)
if meta_tags is not None:
print('Fixing meta-tags')
fixSongM4A(music_file, meta_tags)
else: else:
convertToMP3(music_file) convertToMP3(music_file)
meta_tags = generateMetaTags(raw_song) meta_tags = generateMetaTags(raw_song)
if output_ext == '.m4a':
if meta_tags is not None:
print('Fixing meta-tags')
fixSongM4A(music_file, meta_tags)
elif output_ext == '.mp3':
if meta_tags is not None: if meta_tags is not None:
print('Fixing meta-tags') print('Fixing meta-tags')
fixSong(music_file, meta_tags) fixSong(music_file, meta_tags)
@@ -348,6 +377,9 @@ def getArgs(argv=None):
help='choose the song to download manually', action='store_true') help='choose the song to download manually', action='store_true')
parser.add_argument('-l', '--list', default=False, parser.add_argument('-l', '--list', default=False,
help='download songs present in list.txt', action='store_true') help='download songs present in list.txt', action='store_true')
parser.add_argument('-f', '--ffmpeg', default=False,
help='Use ffmpeg instead of libav for conversion. If not set defaults to libav',
action='store_true')
parser.add_argument('-q', '--quiet', default=False, parser.add_argument('-q', '--quiet', default=False,
help='spare us output of ffmpeg conversion', action='store_true') help='spare us output of ffmpeg conversion', action='store_true')
parser.add_argument('-i', '--input_ext', default='.m4a', parser.add_argument('-i', '--input_ext', default='.m4a',
@@ -364,39 +396,7 @@ def graceQuit():
exit() exit()
if __name__ == '__main__': def spotifyDownload():
# Python 3 compatibility
if version_info > (3, 0):
raw_input = input
eyed3.log.setLevel("ERROR")
os.chdir(path[0])
if not os.path.exists("Music"):
os.makedirs("Music")
open('list.txt', 'a').close()
# Please respect this user token :)
oauth2 = oauth2.SpotifyClientCredentials(client_id='4fe3fecfe5334023a1472516cc99d805',
client_secret='0f02b7c483c04257984695007a4a8d5c')
token = oauth2.get_access_token()
spotify = spotipy.Spotify(auth=token)
# Set up arguments
args = getArgs()
if args.no_convert:
print("-n, --no-convert skip the conversion process and meta-tags")
if args.manual:
print("-m, --manual choose the song to download manually")
print('')
if args.list:
grabList(file='list.txt')
exit()
while True: while True:
for temp in os.listdir('Music/'): for temp in os.listdir('Music/'):
if temp.endswith('.m4a.temp'): if temp.endswith('.m4a.temp'):
@@ -409,3 +409,42 @@ if __name__ == '__main__':
print('') print('')
except KeyboardInterrupt: except KeyboardInterrupt:
graceQuit() graceQuit()
if __name__ == '__main__':
# Python 3 compatibility
if version_info > (3, 0):
raw_input = input
os.chdir(path[0])
if not os.path.exists("Music"):
os.makedirs("Music")
open('list.txt', 'a').close()
# Please respect this user token :)
oauth2 = oauth2.SpotifyClientCredentials(
client_id='4fe3fecfe5334023a1472516cc99d805',
client_secret='0f02b7c483c04257984695007a4a8d5c')
token = oauth2.get_access_token()
spotify = spotipy.Spotify(auth=token)
# Set up arguments
args = getArgs()
if args.ffmpeg:
input_ext = args.input_ext
output_ext = args.output_ext
else:
input_ext = '.m4a'
output_ext = '.mp3'
if args.no_convert:
print("-n, --no-convert skip the conversion process and meta-tags")
if args.manual:
print("-m, --manual choose the song to download manually")
print('')
if args.list:
grabList(file='list.txt')
exit()
eyed3.log.setLevel("ERROR")
spotifyDownload()