mirror of
https://github.com/KevinMidboe/spotify-downloader.git
synced 2025-12-08 20:39:08 +00:00
Merge pull request #121 from lkgarrison/master
Improves accuracy of selected youtube video
This commit is contained in:
@@ -103,9 +103,10 @@ def generate_search_url(song, viewsort=False):
|
|||||||
# urllib.request.quote() encodes URL with special characters
|
# urllib.request.quote() encodes URL with special characters
|
||||||
song = quote(song)
|
song = quote(song)
|
||||||
if viewsort:
|
if viewsort:
|
||||||
url = u"https://www.youtube.com/results?q={0}&sp=CAMSAhABUBQ%253D".format(song)
|
url = u"https://www.youtube.com/results?q={0}".format(song)
|
||||||
else:
|
else:
|
||||||
url = u"https://www.youtube.com/results?sp=EgIQAQ%253D%253D&q={0}".format(song)
|
url = u"https://www.youtube.com/results?sp=EgIQAQ%253D%253D&q={0}".format(song)
|
||||||
|
|
||||||
return url
|
return url
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
51
spotdl.py
51
spotdl.py
@@ -53,8 +53,12 @@ def generate_metadata(raw_song):
|
|||||||
return meta_tags
|
return meta_tags
|
||||||
|
|
||||||
|
|
||||||
def generate_youtube_url(raw_song):
|
def generate_youtube_url(raw_song, tries_remaining=5):
|
||||||
"""Search for the song on YouTube and generate a URL to its video."""
|
"""Search for the song on YouTube and generate a URL to its video."""
|
||||||
|
# prevents an infinite loop but allows for a few retries
|
||||||
|
if tries_remaining == 0:
|
||||||
|
return
|
||||||
|
|
||||||
meta_tags = generate_metadata(raw_song)
|
meta_tags = generate_metadata(raw_song)
|
||||||
if meta_tags is None:
|
if meta_tags is None:
|
||||||
song = raw_song
|
song = raw_song
|
||||||
@@ -69,15 +73,26 @@ def generate_youtube_url(raw_song):
|
|||||||
|
|
||||||
videos = []
|
videos = []
|
||||||
for x in items_parse.find_all('div', {'class': 'yt-lockup-dismissable yt-uix-tile'}):
|
for x in items_parse.find_all('div', {'class': 'yt-lockup-dismissable yt-uix-tile'}):
|
||||||
|
# ensure result is not a channel
|
||||||
|
if x.find('channel') is not None or 'yt-lockup-channel' in x.parent.attrs['class'] or 'yt-lockup-channel' in x.attrs['class']:
|
||||||
|
continue
|
||||||
|
|
||||||
|
# ensure result is not a mix/playlist
|
||||||
|
if 'yt-lockup-playlist' in x.parent.attrs['class']:
|
||||||
|
continue
|
||||||
|
|
||||||
# confirm the video result is not an advertisement
|
# confirm the video result is not an advertisement
|
||||||
if x.find('channel') is None and x.find('googleads') is None:
|
if x.find('googleads') is not None:
|
||||||
|
continue
|
||||||
|
|
||||||
y = x.find('div', class_='yt-lockup-content')
|
y = x.find('div', class_='yt-lockup-content')
|
||||||
link = y.find('a')['href']
|
link = y.find('a')['href']
|
||||||
title = y.find('a')['title']
|
title = y.find('a')['title']
|
||||||
try:
|
try:
|
||||||
videotime = x.find('span', class_="video-time").get_text()
|
videotime = x.find('span', class_="video-time").get_text()
|
||||||
except AttributeError:
|
except AttributeError:
|
||||||
return generate_youtube_url(raw_song)
|
return generate_youtube_url(raw_song, tries_remaining - 1)
|
||||||
|
|
||||||
youtubedetails = {'link': link, 'title': title, 'videotime': videotime, 'seconds':misc.get_sec(videotime)}
|
youtubedetails = {'link': link, 'title': title, 'videotime': videotime, 'seconds':misc.get_sec(videotime)}
|
||||||
videos.append(youtubedetails)
|
videos.append(youtubedetails)
|
||||||
if meta_tags is None:
|
if meta_tags is None:
|
||||||
@@ -100,10 +115,32 @@ def generate_youtube_url(raw_song):
|
|||||||
return None
|
return None
|
||||||
else:
|
else:
|
||||||
if meta_tags is not None:
|
if meta_tags is not None:
|
||||||
videos.sort(key=lambda x: abs(x['seconds'] - (int(meta_tags['duration_ms'])/1000)))
|
# filter out videos that do not have a similar length to the Spotify song
|
||||||
result = videos[0];
|
duration_tolerance = 10
|
||||||
|
max_duration_tolerance = 20
|
||||||
|
possible_videos_by_duration = list()
|
||||||
|
|
||||||
|
'''
|
||||||
|
start with a reasonable duration_tolerance, and increment duration_tolerance
|
||||||
|
until one of the Youtube results falls within the correct duration or
|
||||||
|
the duration_tolerance has reached the max_duration_tolerance
|
||||||
|
'''
|
||||||
|
while len(possible_videos_by_duration) == 0:
|
||||||
|
possible_videos_by_duration = list(filter(lambda x: abs(x['seconds'] - (int(meta_tags['duration_ms'])/1000)) <= duration_tolerance, videos))
|
||||||
|
duration_tolerance += 1
|
||||||
|
if duration_tolerance > max_duration_tolerance:
|
||||||
|
print(meta_tags['name'], 'by', meta_tags['artists'][0]['name'], 'was not found')
|
||||||
|
return None
|
||||||
|
|
||||||
|
result = possible_videos_by_duration[0]
|
||||||
|
else:
|
||||||
|
# if the metadata could not be acquired, take the first result from Youtube because the proper song length is unknown
|
||||||
|
result = videos[0]
|
||||||
|
|
||||||
|
full_link = None
|
||||||
|
if result:
|
||||||
full_link = u'youtube.com{0}'.format(result['link'])
|
full_link = u'youtube.com{0}'.format(result['link'])
|
||||||
|
|
||||||
return full_link
|
return full_link
|
||||||
|
|
||||||
|
|
||||||
@@ -214,6 +251,7 @@ def check_exists(music_file, raw_song, islist=True):
|
|||||||
# do not prompt and skip the current song
|
# do not prompt and skip the current song
|
||||||
# if already downloaded when using list
|
# if already downloaded when using list
|
||||||
if islist:
|
if islist:
|
||||||
|
print('Song already exists')
|
||||||
return True
|
return True
|
||||||
# if downloading only single song, prompt to re-download
|
# if downloading only single song, prompt to re-download
|
||||||
else:
|
else:
|
||||||
@@ -257,7 +295,7 @@ def grab_list(text_file):
|
|||||||
misc.trim_song(text_file)
|
misc.trim_song(text_file)
|
||||||
# and append it to the last line in .txt
|
# and append it to the last line in .txt
|
||||||
with open(text_file, 'a') as myfile:
|
with open(text_file, 'a') as myfile:
|
||||||
myfile.write(raw_song)
|
myfile.write(raw_song + '\n')
|
||||||
print('Failed to download song. Will retry after other songs.')
|
print('Failed to download song. Will retry after other songs.')
|
||||||
continue
|
continue
|
||||||
except KeyboardInterrupt:
|
except KeyboardInterrupt:
|
||||||
@@ -303,6 +341,7 @@ def grab_single(raw_song, number=None):
|
|||||||
content = go_pafy(raw_song)
|
content = go_pafy(raw_song)
|
||||||
if content is None:
|
if content is None:
|
||||||
return
|
return
|
||||||
|
|
||||||
# print '[number]. [artist] - [song]' if downloading from list
|
# print '[number]. [artist] - [song]' if downloading from list
|
||||||
# otherwise print '[artist] - [song]'
|
# otherwise print '[artist] - [song]'
|
||||||
print(get_youtube_title(content, number))
|
print(get_youtube_title(content, number))
|
||||||
|
|||||||
Reference in New Issue
Block a user