Start Media ABC implementation

Signed-off-by: nathom <nathanthomas707@gmail.com>
This commit is contained in:
nathom 2021-07-15 13:38:28 -07:00
parent 4142e1c831
commit 489402165c

View file

@ -55,6 +55,8 @@ TYPE_REGEXES = {
class Media(abc.ABC): class Media(abc.ABC):
__metaclass__ = abc.ABCMeta
@abc.abstractmethod @abc.abstractmethod
def download(self, **kwargs): def download(self, **kwargs):
pass pass
@ -67,11 +69,6 @@ class Media(abc.ABC):
def tag(self, **kwargs): def tag(self, **kwargs):
pass pass
@property
@abc.abstractmethod
def type(self):
pass
@abc.abstractmethod @abc.abstractmethod
def convert(self, **kwargs): def convert(self, **kwargs):
pass pass
@ -84,6 +81,29 @@ class Media(abc.ABC):
def __str__(self): def __str__(self):
pass pass
@property
@abc.abstractmethod
def type(self):
pass
# @property
# @abc.abstractmethod
# def id(self):
# pass
# @id.setter
# def id(self, other):
# pass
@property
@abc.abstractmethod
def downloaded_ids(self):
pass
@downloaded_ids.setter
def downloaded_ids(self, other):
pass
class Track(Media): class Track(Media):
"""Represents a downloadable track. """Represents a downloadable track.
@ -102,6 +122,19 @@ class Track(Media):
>>> t.tag() >>> t.tag()
""" """
id = None
downloaded_ids: set = set()
downloaded: bool = False
tagged: bool = False
converted: bool = False
quality: int
folder: str
meta: TrackMetadata
final_path: str
container: str
def __init__(self, client: Client, **kwargs): def __init__(self, client: Client, **kwargs):
"""Create a track object. """Create a track object.
@ -117,22 +150,13 @@ class Track(Media):
:type meta: Optional[TrackMetadata] :type meta: Optional[TrackMetadata]
:param kwargs: id, filepath_format, meta, quality, folder :param kwargs: id, filepath_format, meta, quality, folder
""" """
logger.debug(kwargs)
self.client = client self.client = client
self.id = None
self.__dict__.update(kwargs) self.__dict__.update(kwargs)
self.downloaded = False
self.tagged = False
self.converted = False
self.part_of_tracklist = kwargs.get("part_of_tracklist", False) self.part_of_tracklist = kwargs.get("part_of_tracklist", False)
self.final_path: str
self.container: str
# TODO: find better solution
for attr in ("quality", "folder", "meta"):
setattr(self, attr, None)
if isinstance(kwargs.get("meta"), TrackMetadata): if isinstance(kwargs.get("meta"), TrackMetadata):
self.meta = kwargs["meta"] self.meta = kwargs["meta"]
@ -373,7 +397,7 @@ class Track(Media):
:rtype: str :rtype: str
""" """
return click.style(f"Track {int(self.meta.tracknumber):02}", fg="blue") return click.style(f"Track {self.meta.tracknumber:02}", fg="blue")
def download_cover(self, width=999999, height=999999): def download_cover(self, width=999999, height=999999):
"""Download the cover art, if cover_url is given.""" """Download the cover art, if cover_url is given."""
@ -645,7 +669,7 @@ class Track(Media):
:param keys: :param keys:
:param default: :param default:
""" """
return safe_get(self.meta, *keys, default=default) return safe_get(self.meta, *keys, default=default) # type: ignore
def set(self, key, val): def set(self, key, val):
"""Set attribute `key` to `val`. """Set attribute `key` to `val`.
@ -821,7 +845,7 @@ class YoutubeVideo(Media):
:param url: URL to the youtube video. :param url: URL to the youtube video.
:type url: str :type url: str
""" """
self.url = url self.id = url
self.client = self.DummyClient() self.client = self.DummyClient()
def download( def download(
@ -842,7 +866,7 @@ class YoutubeVideo(Media):
:type youtube_video_downloads_folder: str :type youtube_video_downloads_folder: str
:param kwargs: :param kwargs:
""" """
click.secho(f"Downloading url {self.url}", fg="blue") click.secho(f"Downloading url {self.id}", fg="blue")
filename_formatter = "%(track_number)s.%(track)s.%(container)s" filename_formatter = "%(track_number)s.%(track)s.%(container)s"
filename = os.path.join(parent_folder, filename_formatter) filename = os.path.join(parent_folder, filename_formatter)
@ -857,7 +881,7 @@ class YoutubeVideo(Media):
"--embed-thumbnail", "--embed-thumbnail",
"-o", "-o",
filename, filename,
self.url, self.id,
] ]
) )
@ -872,7 +896,7 @@ class YoutubeVideo(Media):
youtube_video_downloads_folder, youtube_video_downloads_folder,
"%(title)s.%(container)s", "%(title)s.%(container)s",
), ),
self.url, self.id,
] ]
) )
pv.wait() pv.wait()
@ -1180,6 +1204,10 @@ class Tracklist(list):
def type(self) -> str: def type(self) -> str:
return self.__class__.__name__.lower() return self.__class__.__name__.lower()
@property
def downloaded_ids(self):
raise NotImplementedError
def __getitem__(self, key): def __getitem__(self, key):
"""Get an item if key is int, otherwise get an attr. """Get an item if key is int, otherwise get an attr.
@ -1207,7 +1235,7 @@ class Tracklist(list):
return True return True
class Album(Tracklist): class Album(Tracklist, Media):
"""Represents a downloadable album. """Represents a downloadable album.
Usage: Usage:
@ -1218,6 +1246,9 @@ class Album(Tracklist):
>>> album.download() >>> album.download()
""" """
downloaded_ids: set = set()
id: str
def __init__(self, client: Client, **kwargs): def __init__(self, client: Client, **kwargs):
"""Create a new Album object. """Create a new Album object.
@ -1302,6 +1333,7 @@ class Album(Tracklist):
), f"Invalid cover size. Must be in {self.cover_urls.keys()}" ), f"Invalid cover size. Must be in {self.cover_urls.keys()}"
embed_cover_url = self.cover_urls[embed_cover_size] embed_cover_url = self.cover_urls[embed_cover_size]
if not os.path.exists(cover_path):
if embed_cover_url is not None: if embed_cover_url is not None:
tqdm_download(embed_cover_url, cover_path) tqdm_download(embed_cover_url, cover_path)
else: # sometimes happens with Deezer else: # sometimes happens with Deezer
@ -1375,6 +1407,8 @@ class Album(Tracklist):
embed_cover=kwargs.get("embed_cover", True), embed_cover=kwargs.get("embed_cover", True),
) )
self.downloaded_ids.add(item.id)
@staticmethod @staticmethod
def _parse_get_resp(resp: dict, client: Client) -> TrackMetadata: def _parse_get_resp(resp: dict, client: Client) -> TrackMetadata:
"""Parse information from a client.get(query, 'album') call. """Parse information from a client.get(query, 'album') call.
@ -1499,7 +1533,7 @@ class Album(Tracklist):
return hash(self.id) return hash(self.id)
class Playlist(Tracklist): class Playlist(Tracklist, Media):
"""Represents a downloadable playlist. """Represents a downloadable playlist.
Usage: Usage:
@ -1509,6 +1543,9 @@ class Playlist(Tracklist):
>>> pl.download() >>> pl.download()
""" """
id = None
downloaded_ids: set = set()
def __init__(self, client: Client, **kwargs): def __init__(self, client: Client, **kwargs):
"""Create a new Playlist object. """Create a new Playlist object.
@ -1519,6 +1556,7 @@ class Playlist(Tracklist):
""" """
self.name: str self.name: str
self.client = client self.client = client
logger.debug(kwargs)
for k, v in kwargs.items(): for k, v in kwargs.items():
setattr(self, k, v) setattr(self, k, v)
@ -1667,6 +1705,8 @@ class Playlist(Tracklist):
audio["TRACKNUMBER"] = f"{item['tracknumber']:02}" audio["TRACKNUMBER"] = f"{item['tracknumber']:02}"
audio.save() audio.save()
self.downloaded_ids.add(item.id)
@staticmethod @staticmethod
def _parse_get_resp(item: dict, client: Client) -> dict: def _parse_get_resp(item: dict, client: Client) -> dict:
"""Parse information from a search result returned by a client.search call. """Parse information from a search result returned by a client.search call.
@ -1717,6 +1757,9 @@ class Playlist(Tracklist):
""" """
return f"<Playlist: {self.name}>" return f"<Playlist: {self.name}>"
def tag(self):
raise NotImplementedError
def __str__(self) -> str: def __str__(self) -> str:
"""Return a readable string representation of this track. """Return a readable string representation of this track.
@ -1725,7 +1768,7 @@ class Playlist(Tracklist):
return f"{self.name} ({len(self)} tracks)" return f"{self.name} ({len(self)} tracks)"
class Artist(Tracklist): class Artist(Tracklist, Media):
"""Represents a downloadable artist. """Represents a downloadable artist.
Usage: Usage:
@ -1744,6 +1787,7 @@ class Artist(Tracklist):
:param kwargs: :param kwargs:
""" """
self.client = client self.client = client
self.downloaded_ids: set = set()
for k, v in kwargs.items(): for k, v in kwargs.items():
setattr(self, k, v) setattr(self, k, v)
@ -1842,7 +1886,11 @@ class Artist(Tracklist):
:param kwargs: :param kwargs:
:rtype: bool :rtype: bool
""" """
try:
item.load_meta() item.load_meta()
except NonStreamable as e:
e.print(item)
return
kwargs.pop("parent_folder") kwargs.pop("parent_folder")
# always an Album # always an Album
@ -1850,6 +1898,7 @@ class Artist(Tracklist):
parent_folder=self.folder, parent_folder=self.folder,
**kwargs, **kwargs,
) )
self.downloaded_ids.update(item.downloaded_ids)
@property @property
def title(self) -> str: def title(self) -> str: