From bdf05adcb1fa87c24bf1d245e08dfa46fc24b799 Mon Sep 17 00:00:00 2001 From: Hellow2 Date: Mon, 3 Apr 2023 09:43:45 +0200 Subject: [PATCH] cleaned up download --- src/music_kraken/__init__.py | 2 +- .../pages/download_center/multiple_options.py | 100 ++++++++++ .../pages/download_center/search.py | 174 +++++------------- 3 files changed, 146 insertions(+), 130 deletions(-) create mode 100644 src/music_kraken/pages/download_center/multiple_options.py diff --git a/src/music_kraken/__init__.py b/src/music_kraken/__init__.py index 6f46644..587d714 100644 --- a/src/music_kraken/__init__.py +++ b/src/music_kraken/__init__.py @@ -72,7 +72,7 @@ def cli(): print("The given url couldn't be downloaded") return - page = search.get_page_from_query(parsed) + page = search._get_page_from_query(parsed) if page is not None: search.choose_page(page) return diff --git a/src/music_kraken/pages/download_center/multiple_options.py b/src/music_kraken/pages/download_center/multiple_options.py new file mode 100644 index 0000000..8326a66 --- /dev/null +++ b/src/music_kraken/pages/download_center/multiple_options.py @@ -0,0 +1,100 @@ +from collections import defaultdict +from typing import Tuple, List, Dict, Type + +from . import page_attributes +from ..abstract import Page +from ...objects import Options, DatabaseObject, Source + + +class MultiPageOptions: + def __init__( + self, + max_displayed_options: int = 10, + option_digits: int = 3, + derived_from: DatabaseObject = None + ) -> None: + self.max_displayed_options = max_displayed_options + self.option_digits: int = option_digits + + self._length = 0 + self._current_option_dict: Dict[Type[Page], Options] = defaultdict(lambda: Options()) + + self._derive_from = derived_from + + def __getitem__(self, key: Type[Page]): + return self._current_option_dict[key] + + def __setitem__(self, key: Type[Page], value: Options): + self._current_option_dict[key] = value + + self._length = 0 + for key in self._current_option_dict: + self._length += 1 + + def __len__(self) -> int: + return self._length + + def get_page_str(self, page: Type[Page]) -> str: + page_name_fill = "-" + max_page_len = 21 + + return f"({page_attributes.PAGE_NAME_MAP[page]}) ------------------------{page.__name__:{page_name_fill}<{max_page_len}}------------" + + def string_from_all_pages(self) -> str: + if self._length == 1: + for key in self._current_option_dict: + return self.string_from_single_page(key) + + lines: List[str] = [] + + j = 0 + for page, options in self._current_option_dict.items(): + lines.append(self.get_page_str(page)) + + i = -1 + + option_obj: DatabaseObject + for i, option_obj in enumerate(options): + if i >= self.max_displayed_options: + lines.append("...") + break + + lines.append(f"{j + i:0{self.option_digits}} {option_obj.option_string}") + + j += i + 1 + + return "\n".join(lines) + + def choose_from_all_pages(self, index: int) -> Tuple[DatabaseObject, Type[Page]]: + if self._length == 1: + for key in self._current_option_dict: + return self.choose_from_single_page(key, index), key + + sum_of_length = 0 + for page, options in self._current_option_dict.items(): + option_len = min((len(options), self.max_displayed_options)) + + index_of_list = index - sum_of_length + + if index_of_list < option_len: + return options[index_of_list], page + + sum_of_length += option_len + + raise IndexError("index is out of range") + + def string_from_single_page(self, page: Type[Page]) -> str: + lines: List[str] = [self.get_page_str(page)] + + option_obj: DatabaseObject + for i, option_obj in enumerate(self._current_option_dict[page]): + lines.append(f"{i:0{self.option_digits}} {option_obj.option_string}") + + return "\n".join(lines) + + def choose_from_single_page(self, page: Type[Page], index: int) -> DatabaseObject: + return self._current_option_dict[page][index] + + def __repr__(self) -> str: + return self.string_from_all_pages() + \ No newline at end of file diff --git a/src/music_kraken/pages/download_center/search.py b/src/music_kraken/pages/download_center/search.py index cf0867d..9717838 100644 --- a/src/music_kraken/pages/download_center/search.py +++ b/src/music_kraken/pages/download_center/search.py @@ -3,117 +3,10 @@ from typing import Tuple, List, Set, Dict, Type, Union, Optional from . import page_attributes from .download import Download +from .multiple_options import MultiPageOptions from ..abstract import Page from ...objects import Options, DatabaseObject, Source - - -class MultiPageOptions: - def __init__( - self, - max_displayed_options: int = 10, - option_digits: int = 3, - database_object: DatabaseObject = None, - page: Type[Page] = None - ) -> None: - self.max_displayed_options = max_displayed_options - self.option_digits: int = option_digits - - self._length = 0 - self._current_option_dict: Dict[Type[Page], Options] = defaultdict(lambda: Options()) - - self.database_object = database_object - self.page = page - - if database_object is not None and page is not None: - self[page] = database_object.options - - def __getitem__(self, key: Type[Page]): - return self._current_option_dict[key] - - def __setitem__(self, key: Type[Page], value: Options): - self._current_option_dict[key] = value - - self._length = 0 - for key in self._current_option_dict: - self._length += 1 - - def __len__(self) -> int: - return self._length - - def get_page_str(self, page: Type[Page]) -> str: - page_name_fill = "-" - max_page_len = 21 - - return f"({page_attributes.PAGE_NAME_MAP[page]}) ------------------------{page.__name__:{page_name_fill}<{max_page_len}}------------" - - def string_from_all_pages(self) -> str: - if self._length == 1: - for key in self._current_option_dict: - return self.string_from_single_page(key) - - lines: List[str] = [] - - j = 0 - for page, options in self._current_option_dict.items(): - lines.append(self.get_page_str(page)) - - i = -1 - - option_obj: DatabaseObject - for i, option_obj in enumerate(options): - if i >= self.max_displayed_options: - lines.append("...") - break - - lines.append(f"{j + i:0{self.option_digits}} {option_obj.option_string}") - - j += i + 1 - - return "\n".join(lines) - - def choose_from_all_pages(self, index: int) -> Tuple[DatabaseObject, Type[Page]]: - if self._length == 1: - for key in self._current_option_dict: - return self.choose_from_single_page(key, index), key - - sum_of_length = 0 - for page, options in self._current_option_dict.items(): - option_len = min((len(options), self.max_displayed_options)) - - index_of_list = index - sum_of_length - - if index_of_list < option_len: - return options[index_of_list], page - - sum_of_length += option_len - - raise IndexError("index is out of range") - - def string_from_single_page(self, page: Type[Page]) -> str: - lines: List[str] = [self.get_page_str(page)] - - option_obj: DatabaseObject - for i, option_obj in enumerate(self._current_option_dict[page]): - lines.append(f"{i:0{self.option_digits}} {option_obj.option_string}") - - return "\n".join(lines) - - def choose_from_single_page(self, page: Type[Page], index: int) -> DatabaseObject: - return self._current_option_dict[page][index] - - def __repr__(self) -> str: - return self.string_from_all_pages() - - def download(self) -> bool: - if self._length != 1: - return False - - if self.database_object is None or self.page is None: - return False - - self.page.download(self.database_object) - - return True +from ...utils.shared import DOWNLOAD_LOGGER as LOGGER class Search(Download): @@ -141,32 +34,23 @@ class Search(Download): def __repr__(self): return self._current_option.__repr__() - - @property - def next_options(self) -> MultiPageOptions: - mpo = MultiPageOptions( - max_displayed_options=self.max_displayed_options, - option_digits=self.option_digits - ) - self._option_history.append(mpo) - self._current_option = mpo - return mpo - def next_options_from_music_obj(self, database_obj: DatabaseObject, page: Type[Page]) -> MultiPageOptions: + def next_options(self, derive_from: DatabaseObject = None) -> MultiPageOptions: mpo = MultiPageOptions( max_displayed_options=self.max_displayed_options, option_digits=self.option_digits, - database_object=database_obj, - page=page + derived_from=derive_from ) + self._option_history.append(mpo) self._current_option = mpo + return mpo - @property def _previous_options(self) -> MultiPageOptions: self._option_history.pop() self._current_option = self._option_history[-1] + return self._option_history[-1] def search(self, query: str): @@ -177,40 +61,62 @@ class Search(Download): the letter behind it defines the *type* of parameter, followed by a space "#a Psychonaut 4 #r Tired, Numb and #t Drop by Drop" if no # is in the query it gets treated as "unspecified query" + + doesn't set derived_from thus, + can't download right after """ for page in self.pages: self._current_option[page] = page.search_by_query(query=query) def choose_page(self, page: Type[Page]): + """ + doesn't set derived_from thus, + can't download right after + """ + if page not in page_attributes.ALL_PAGES: raise ValueError(f"Page \"{page.__name__}\" does not exist in page_attributes.ALL_PAGES") prev_mpo = self._current_option - mpo = self.next_options + mpo = self.next_options() mpo[page] = prev_mpo[page] - def get_page_from_query(self, query: str) -> Optional[Type[Page]]: + def _get_page_from_query(self, query: str) -> Optional[Type[Page]]: + """ + query can be for example: + "a" or "EncyclopaediaMetallum" to choose a page + """ + page = page_attributes.NAME_PAGE_MAP.get(query.lower().strip()) if page in self.pages: return page + + def _get_page_from_source(self, source: Source) -> Optional[Type[Page]]: + return page_attributes.SOURCE_PAGE_MAP.get(source.page_enum) def choose_index(self, index: int): db_object, page = self._current_option.choose_from_all_pages(index=index) music_object = self.fetch_details(db_object) - mpo = self.next_options_from_music_obj(music_object, page) + mpo[page] = music_object.options + def goto_previous(self): try: - self._current_option = self._previous_options + self._previous_options() except IndexError: pass def search_url(self, url: str) -> bool: + """ + sets derived_from, thus + can download directly after + """ + source = Source.match_url(url=url) if source is None: return False @@ -220,10 +126,20 @@ class Search(Download): return False page = page_attributes.SOURCE_PAGE_MAP[source.page_enum] - mpo = self.next_options + mpo = self.next_options(derive_from=new_object) mpo[page] = new_object.options return True def download_chosen(self) -> bool: - return self._current_option.download() + if self._current_option._derive_from is None: + LOGGER.warning(f"can't download from an non choosen stuff") + return False + + source: Source + for source in self._current_option._derive_from.source_collection: + page = self._get_page_from_source(source=source) + + if page in self.audio_pages: + return page.download(music_object=self._current_option._derive_from) +