mirror of
https://github.com/KevinMidboe/spotify-downloader.git
synced 2025-10-29 18:00:15 +00:00
Use YouTube as fallback for track metadata if not found on Spotify
This commit is contained in:
@@ -1,6 +1,7 @@
|
||||
from logzero import logger as log
|
||||
import os
|
||||
import sys
|
||||
import urllib.request
|
||||
|
||||
from spotdl import const
|
||||
|
||||
@@ -253,3 +254,12 @@ def remove_duplicates(tracks):
|
||||
local_set = set()
|
||||
local_set_add = local_set.add
|
||||
return [x for x in tracks if not (x in local_set or local_set_add(x))]
|
||||
|
||||
|
||||
def content_available(url):
|
||||
try:
|
||||
response = urllib.request.urlopen(url)
|
||||
except HTTPError:
|
||||
return False
|
||||
else:
|
||||
return response.getcode() < 300
|
||||
|
||||
@@ -46,6 +46,8 @@ class EmbedMetadata:
|
||||
def __init__(self, music_file, meta_tags):
|
||||
self.music_file = music_file
|
||||
self.meta_tags = meta_tags
|
||||
self.spotify_metadata = meta_tags["spotify_metadata"]
|
||||
self.provider = "spotify" if meta_tags["spotify_metadata"] else "youtube"
|
||||
|
||||
def as_mp3(self):
|
||||
""" Embed metadata to MP3 files. """
|
||||
@@ -62,7 +64,7 @@ class EmbedMetadata:
|
||||
audiofile["lyricist"] = meta_tags["artists"][0]["name"]
|
||||
audiofile["arranger"] = meta_tags["artists"][0]["name"]
|
||||
audiofile["performer"] = meta_tags["artists"][0]["name"]
|
||||
audiofile["website"] = meta_tags["external_urls"]["spotify"]
|
||||
audiofile["website"] = meta_tags["external_urls"][self.provider]
|
||||
audiofile["length"] = str(meta_tags["duration"])
|
||||
if meta_tags["publisher"]:
|
||||
audiofile["encodedby"] = meta_tags["publisher"]
|
||||
@@ -78,7 +80,7 @@ class EmbedMetadata:
|
||||
audiofile["TYER"] = TYER(encoding=3, text=meta_tags["year"])
|
||||
if meta_tags["publisher"]:
|
||||
audiofile["TPUB"] = TPUB(encoding=3, text=meta_tags["publisher"])
|
||||
audiofile["COMM"] = COMM(encoding=3, text=meta_tags["external_urls"]["spotify"])
|
||||
audiofile["COMM"] = COMM(encoding=3, text=meta_tags["external_urls"][self.provider])
|
||||
if meta_tags["lyrics"]:
|
||||
audiofile["USLT"] = USLT(
|
||||
encoding=3, desc=u"Lyrics", text=meta_tags["lyrics"]
|
||||
@@ -106,7 +108,7 @@ class EmbedMetadata:
|
||||
audiofile = MP4(music_file)
|
||||
self._embed_basic_metadata(audiofile, preset=M4A_TAG_PRESET)
|
||||
audiofile[M4A_TAG_PRESET["year"]] = meta_tags["year"]
|
||||
audiofile[M4A_TAG_PRESET["comment"]] = meta_tags["external_urls"]["spotify"]
|
||||
audiofile[M4A_TAG_PRESET["comment"]] = meta_tags["external_urls"][self.provider]
|
||||
if meta_tags["lyrics"]:
|
||||
audiofile[M4A_TAG_PRESET["lyrics"]] = meta_tags["lyrics"]
|
||||
try:
|
||||
@@ -127,7 +129,7 @@ class EmbedMetadata:
|
||||
audiofile = FLAC(music_file)
|
||||
self._embed_basic_metadata(audiofile)
|
||||
audiofile["year"] = meta_tags["year"]
|
||||
audiofile["comment"] = meta_tags["external_urls"]["spotify"]
|
||||
audiofile["comment"] = meta_tags["external_urls"][self.provider]
|
||||
if meta_tags["lyrics"]:
|
||||
audiofile["lyrics"] = meta_tags["lyrics"]
|
||||
|
||||
@@ -147,7 +149,8 @@ class EmbedMetadata:
|
||||
meta_tags = self.meta_tags
|
||||
audiofile[preset["artist"]] = meta_tags["artists"][0]["name"]
|
||||
audiofile[preset["albumartist"]] = meta_tags["album"]["artists"][0]["name"]
|
||||
audiofile[preset["album"]] = meta_tags["album"]["name"]
|
||||
if meta_tags["album"]["name"]:
|
||||
audiofile[preset["album"]] = meta_tags["album"]["name"]
|
||||
audiofile[preset["title"]] = meta_tags["name"]
|
||||
audiofile[preset["date"]] = meta_tags["release_date"]
|
||||
audiofile[preset["originaldate"]] = meta_tags["release_date"]
|
||||
|
||||
31
spotdl/patcher.py
Normal file
31
spotdl/patcher.py
Normal file
@@ -0,0 +1,31 @@
|
||||
import pafy
|
||||
|
||||
from spotdl import internals
|
||||
|
||||
|
||||
def _getbestthumb(self):
|
||||
url = self._ydl_info["thumbnails"][0]["url"]
|
||||
if url:
|
||||
return url
|
||||
|
||||
part_url = "http://i.ytimg.com/vi/%s/" % self.videoid
|
||||
# Thumbnail resolution sorted in descending order
|
||||
thumbs = ("maxresdefault.jpg",
|
||||
"sddefault.jpg",
|
||||
"hqdefault.jpg",
|
||||
"mqdefault.jpg",
|
||||
"default.jpg")
|
||||
for thumb in thumbs:
|
||||
url = part_url + thumb
|
||||
if self._content_available(url):
|
||||
return url
|
||||
|
||||
|
||||
@classmethod
|
||||
def _content_available(cls, url):
|
||||
return internals.content_available(url)
|
||||
|
||||
def patch_pafy():
|
||||
pafy.backend_shared.BasePafy._bestthumb = None
|
||||
pafy.backend_shared.BasePafy._content_available = _content_available
|
||||
pafy.backend_shared.BasePafy.getbestthumb = _getbestthumb
|
||||
@@ -81,6 +81,7 @@ def generate_metadata(raw_song):
|
||||
# Some sugar
|
||||
meta_tags["year"], *_ = meta_tags["release_date"].split("-")
|
||||
meta_tags["duration"] = meta_tags["duration_ms"] / 1000.0
|
||||
meta_tags["spotify_metadata"] = True
|
||||
# Remove unwanted parameters
|
||||
del meta_tags["duration_ms"]
|
||||
del meta_tags["available_markets"]
|
||||
|
||||
@@ -14,6 +14,12 @@ from spotdl import const
|
||||
# Read more on mps-youtube/pafy#199
|
||||
pafy.g.opener.addheaders.append(("Range", "bytes=0-"))
|
||||
|
||||
# Implement unreleased methods on Pafy object
|
||||
# More info: https://github.com/mps-youtube/pafy/pull/211
|
||||
if pafy.__version__ <= "0.5.4":
|
||||
from spotdl import patcher
|
||||
patcher.patch_pafy()
|
||||
|
||||
|
||||
def set_api_key():
|
||||
if const.args.youtube_api_key:
|
||||
@@ -49,6 +55,8 @@ def match_video_and_metadata(track, force_pafy=True):
|
||||
track = slugify(content.title).replace("-", " ")
|
||||
if not const.args.no_metadata:
|
||||
meta_tags = spotify_tools.generate_metadata(track)
|
||||
if meta_tags is None: # and const.args.allow_youtube:
|
||||
meta_tags = generate_metadata(content)
|
||||
else:
|
||||
# Let it generate metadata, youtube doesn't know spotify slang
|
||||
if not const.args.no_metadata or internals.is_spotify(track):
|
||||
@@ -56,11 +64,37 @@ def match_video_and_metadata(track, force_pafy=True):
|
||||
|
||||
if force_pafy:
|
||||
content = go_pafy(track, meta_tags)
|
||||
if meta_tags is None: # and const.args.allow_youtube:
|
||||
meta_tags = generate_metadata(content)
|
||||
else:
|
||||
content = None
|
||||
return content, meta_tags
|
||||
|
||||
|
||||
def generate_metadata(content):
|
||||
""" Fetch a song's metadata from YouTube. """
|
||||
meta_tags = {"spotify_metadata": False,
|
||||
"name": content.title,
|
||||
"artists": [{"name": content.author}],
|
||||
"duration": content.length,
|
||||
"external_urls": {"youtube": content.watchv_url},
|
||||
"album": {"images" : [{"url": content.getbestthumb()}], "name": None},
|
||||
"year": content.published.split("-")[0],
|
||||
"release_date": content.published.split(" ")[0],
|
||||
"type": "track",
|
||||
"disc_number": 1,
|
||||
"track_number": 1,
|
||||
"total_tracks": 1,
|
||||
"publisher": None,
|
||||
"external_ids": {"isrc": None},
|
||||
"lyrics": None,
|
||||
"copyright": None,
|
||||
"genre": None,
|
||||
}
|
||||
|
||||
return meta_tags
|
||||
|
||||
|
||||
def get_youtube_title(content, number=None):
|
||||
""" Get the YouTube video's title. """
|
||||
title = content.title
|
||||
|
||||
Reference in New Issue
Block a user