Add support for Youtube urls

This commit is contained in:
nathom 2021-04-22 17:22:33 -07:00
parent 10ceecb55c
commit 7347330a42
6 changed files with 63 additions and 10 deletions

1
.gitignore vendored
View File

@ -17,3 +17,4 @@ StreamripDownloads
*.mkv *.mkv
*.aac *.aac
*.pyc *.pyc
*test.py

View File

@ -765,7 +765,7 @@ class Tracklist(list):
else: else:
for item in self: for item in self:
if self.client.source != 'soundcloud': if self.client.source != "soundcloud":
# soundcloud only gets metadata after `target` is called # soundcloud only gets metadata after `target` is called
# message will be printed in `target` # message will be printed in `target`
click.secho(f'\nDownloading "{item!s}"', fg="blue") click.secho(f'\nDownloading "{item!s}"', fg="blue")
@ -951,3 +951,39 @@ class Tracklist(list):
if isinstance(key, int): if isinstance(key, int):
super().__setitem__(key, val) super().__setitem__(key, val)
class YoutubeVideo:
"""Dummy class implemented for consistency with the Media API."""
class DummyClient:
source = 'youtube'
def __init__(self, url: str):
self.url = url
self.client = self.DummyClient()
def download(self, parent_folder='StreamripDownloads', **kwargs):
filename_formatter = "%(track_number)s.%(track)s.%(container)s"
filename = os.path.join(parent_folder, filename_formatter)
p = subprocess.Popen(
[
"youtube-dl",
"-x",
"--add-metadata",
"--audio-format",
"mp3",
"--embed-thumbnail",
"-o",
filename,
self.url,
]
)
p.wait()
def load_meta(self, *args, **kwargs):
pass
def tag(self, *args, **kwargs):
pass

View File

@ -69,6 +69,9 @@ class Config:
"soundcloud": { "soundcloud": {
"quality": 0, "quality": 0,
}, },
"youtube": {
"quality": 0,
},
"database": {"enabled": True, "path": None}, "database": {"enabled": True, "path": None},
"conversion": { "conversion": {
"enabled": False, "enabled": False,

View File

@ -145,7 +145,7 @@ LASTFM_URL_REGEX = r"https://www.last.fm/user/\w+/playlists/\w+"
QOBUZ_INTERPRETER_URL_REGEX = ( QOBUZ_INTERPRETER_URL_REGEX = (
r"https?://www\.qobuz\.com/\w\w-\w\w/interpreter/[-\w]+/[-\w]+" r"https?://www\.qobuz\.com/\w\w-\w\w/interpreter/[-\w]+/[-\w]+"
) )
YOUTUBE_URL_REGEX = r"https://www\.youtube\.com/watch\?v=\w+"
TIDAL_MAX_Q = 7 TIDAL_MAX_Q = 7

View File

@ -12,13 +12,14 @@ import click
import requests import requests
from tqdm import tqdm from tqdm import tqdm
from .bases import Track, Video from .bases import Track, Video, YoutubeVideo
from .clients import DeezerClient, QobuzClient, SoundCloudClient, TidalClient from .clients import DeezerClient, QobuzClient, SoundCloudClient, TidalClient
from .config import Config from .config import Config
from .constants import ( from .constants import (
CONFIG_PATH, CONFIG_PATH,
DB_PATH, DB_PATH,
LASTFM_URL_REGEX, LASTFM_URL_REGEX,
YOUTUBE_URL_REGEX,
MEDIA_TYPES, MEDIA_TYPES,
QOBUZ_INTERPRETER_URL_REGEX, QOBUZ_INTERPRETER_URL_REGEX,
SOUNDCLOUD_URL_REGEX, SOUNDCLOUD_URL_REGEX,
@ -58,6 +59,7 @@ class MusicDL(list):
self.soundcloud_url_parse = re.compile(SOUNDCLOUD_URL_REGEX) self.soundcloud_url_parse = re.compile(SOUNDCLOUD_URL_REGEX)
self.lastfm_url_parse = re.compile(LASTFM_URL_REGEX) self.lastfm_url_parse = re.compile(LASTFM_URL_REGEX)
self.interpreter_url_parse = re.compile(QOBUZ_INTERPRETER_URL_REGEX) self.interpreter_url_parse = re.compile(QOBUZ_INTERPRETER_URL_REGEX)
self.youtube_url_parse = re.compile(YOUTUBE_URL_REGEX)
self.config = config self.config = config
if self.config is None: if self.config is None:
@ -89,7 +91,17 @@ class MusicDL(list):
:raises ParsingError :raises ParsingError
""" """
for source, url_type, item_id in self.parse_urls(url): # youtube is handled by youtube-dl, so much of the
# processing is not necessary
youtube_urls = self.youtube_url_parse.findall(url)
if youtube_urls != []:
self.extend(YoutubeVideo(u) for u in youtube_urls)
parsed = self.parse_urls(url)
if not parsed and len(self) == 0:
raise ParsingError(url)
for source, url_type, item_id in parsed:
if item_id in self.db: if item_id in self.db:
logger.info( logger.info(
f"ID {item_id} already downloaded, use --no-db to override." f"ID {item_id} already downloaded, use --no-db to override."
@ -170,6 +182,10 @@ class MusicDL(list):
item.client.source item.client.source
) )
if item is YoutubeVideo:
item.download(**arguments)
continue
arguments["quality"] = self.config.session[item.client.source]["quality"] arguments["quality"] = self.config.session[item.client.source]["quality"]
if isinstance(item, Artist): if isinstance(item, Artist):
filters_ = tuple( filters_ = tuple(
@ -266,10 +282,7 @@ class MusicDL(list):
logger.debug(f"Parsed urls: {parsed}") logger.debug(f"Parsed urls: {parsed}")
if parsed != []: return parsed
return parsed
raise ParsingError(f"Error parsing URL: `{url}`")
def handle_lastfm_urls(self, urls): def handle_lastfm_urls(self, urls):
# https://www.last.fm/user/nathan3895/playlists/12058911 # https://www.last.fm/user/nathan3895/playlists/12058911

View File

@ -415,10 +415,10 @@ class Playlist(Tracklist):
self.download_message() self.download_message()
def _download_item(self, item: Track, **kwargs): def _download_item(self, item: Track, **kwargs):
kwargs['parent_folder'] = self.folder kwargs["parent_folder"] = self.folder
if self.client.source == "soundcloud": if self.client.source == "soundcloud":
item.load_meta() item.load_meta()
click.secho(f"Downloading {item!s}", fg='blue') click.secho(f"Downloading {item!s}", fg="blue")
if kwargs.get("set_playlist_to_album", False): if kwargs.get("set_playlist_to_album", False):
item["album"] = self.name item["album"] = self.name