This commit is contained in:
parent
c0fbd16929
commit
cef87460a7
6
.vscode/launch.json
vendored
6
.vscode/launch.json
vendored
@ -17,6 +17,12 @@
|
|||||||
"request": "launch",
|
"request": "launch",
|
||||||
"program": "development/actual_donwload.py",
|
"program": "development/actual_donwload.py",
|
||||||
"console": "integratedTerminal"
|
"console": "integratedTerminal"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Python Debugger: Music Kraken",
|
||||||
|
"type": "debugpy",
|
||||||
|
"request": "launch", // run the module
|
||||||
|
"module": "music_kraken",
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
@ -4,10 +4,9 @@ from pathlib import Path
|
|||||||
from typing import Dict, List, Set, Type
|
from typing import Dict, List, Set, Type
|
||||||
|
|
||||||
from .. import console
|
from .. import console
|
||||||
from ..download import Downloader
|
from ..download import Downloader, Page
|
||||||
from ..download.results import GoToResults, Option, PageResults, Results
|
from ..download.results import GoToResults, Option, PageResults, Results
|
||||||
from ..objects import Album, Artist, DatabaseObject, Song
|
from ..objects import Album, Artist, DatabaseObject, Song
|
||||||
from ..pages import Page
|
|
||||||
from ..utils import BColors, output
|
from ..utils import BColors, output
|
||||||
from ..utils.config import main_settings, write_config
|
from ..utils.config import main_settings, write_config
|
||||||
from ..utils.enums.colors import BColors
|
from ..utils.enums.colors import BColors
|
||||||
|
@ -8,8 +8,8 @@ from copy import copy
|
|||||||
from dataclasses import dataclass, field
|
from dataclasses import dataclass, field
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
from string import Formatter
|
from string import Formatter
|
||||||
from typing import (TYPE_CHECKING, Dict, List, Optional, Set, Tuple, Type,
|
from typing import (TYPE_CHECKING, Any, Callable, Dict, Generator, List,
|
||||||
TypedDict, Union)
|
Optional, Set, Tuple, Type, TypedDict, Union)
|
||||||
|
|
||||||
import requests
|
import requests
|
||||||
from bs4 import BeautifulSoup
|
from bs4 import BeautifulSoup
|
||||||
@ -23,7 +23,7 @@ from ..utils import BColors, output, trace
|
|||||||
from ..utils.config import main_settings, youtube_settings
|
from ..utils.config import main_settings, youtube_settings
|
||||||
from ..utils.enums import ALL_SOURCE_TYPES, SourceType
|
from ..utils.enums import ALL_SOURCE_TYPES, SourceType
|
||||||
from ..utils.enums.album import AlbumType
|
from ..utils.enums.album import AlbumType
|
||||||
from ..utils.exception import MKMissingNameException
|
from ..utils.exception import MKComposeException, MKMissingNameException
|
||||||
from ..utils.exception.download import UrlNotFoundException
|
from ..utils.exception.download import UrlNotFoundException
|
||||||
from ..utils.path_manager import LOCATIONS
|
from ..utils.path_manager import LOCATIONS
|
||||||
from ..utils.shared import DEBUG_PAGES
|
from ..utils.shared import DEBUG_PAGES
|
||||||
@ -75,7 +75,7 @@ class Downloader:
|
|||||||
self.scan_for_pages(**kwargs)
|
self.scan_for_pages(**kwargs)
|
||||||
|
|
||||||
def register_page(self, page_type: Type[Page], **kwargs):
|
def register_page(self, page_type: Type[Page], **kwargs):
|
||||||
if page_type in _registered_pages:
|
if page_type in self._registered_pages:
|
||||||
return
|
return
|
||||||
|
|
||||||
self._registered_pages[page_type].add(page_type(
|
self._registered_pages[page_type].add(page_type(
|
||||||
@ -343,12 +343,14 @@ class Page:
|
|||||||
return super().__new__(cls)
|
return super().__new__(cls)
|
||||||
|
|
||||||
def __init__(self, download_options: DownloadOptions = None, fetch_options: FetchOptions = None, **kwargs):
|
def __init__(self, download_options: DownloadOptions = None, fetch_options: FetchOptions = None, **kwargs):
|
||||||
|
if self.SOURCE_TYPE is not None:
|
||||||
self.SOURCE_TYPE.register_page(self)
|
self.SOURCE_TYPE.register_page(self)
|
||||||
|
|
||||||
self.download_options: DownloadOptions = download_options or DownloadOptions()
|
self.download_options: DownloadOptions = download_options or DownloadOptions()
|
||||||
self.fetch_options: FetchOptions = fetch_options or FetchOptions()
|
self.fetch_options: FetchOptions = fetch_options or FetchOptions()
|
||||||
|
|
||||||
def __del__(self):
|
def __del__(self):
|
||||||
|
if self.SOURCE_TYPE is not None:
|
||||||
self.SOURCE_TYPE.deregister_page()
|
self.SOURCE_TYPE.deregister_page()
|
||||||
|
|
||||||
def _search_regex(self, pattern, string, default=None, fatal=True, flags=0, group=None):
|
def _search_regex(self, pattern, string, default=None, fatal=True, flags=0, group=None):
|
||||||
@ -451,23 +453,73 @@ class Option:
|
|||||||
This could represent a data object, a string or a page.
|
This could represent a data object, a string or a page.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
def __init__(self, value: Any, text: Optional[str] = None, keys: Set[str] = None, hidden: bool = False):
|
def __init__(
|
||||||
|
self,
|
||||||
|
value: Any,
|
||||||
|
text: Optional[str] = None,
|
||||||
|
keys: List[Any] = None,
|
||||||
|
hidden: bool = False,
|
||||||
|
parse_key: Callable[[Any], Any] = lambda x: x,
|
||||||
|
):
|
||||||
|
self._parse_key: Callable[[Any], Any] = parse_key
|
||||||
|
|
||||||
self.value = value
|
self.value = value
|
||||||
self.text = text or str(value)
|
self.text = text or str(value)
|
||||||
self.hidden = hidden
|
self.hidden = hidden
|
||||||
|
|
||||||
self.keys = keys or set()
|
self._raw_keys = set(keys or [])
|
||||||
self.keys.add(self.text)
|
self._raw_keys.add(self.text)
|
||||||
|
self.keys = set(self.parse_key(key) for key in self._raw_keys)
|
||||||
|
|
||||||
|
def register_key(self, key: Any):
|
||||||
|
self._raw_keys.add(key)
|
||||||
|
self.keys.add(self._parse_key(key))
|
||||||
|
|
||||||
|
@property
|
||||||
|
def parse_key(self) -> Callable[[Any], Any]:
|
||||||
|
return self._parse_key
|
||||||
|
|
||||||
|
@parse_key.setter
|
||||||
|
def parse_key(self, value: Callable[[Any], Any]):
|
||||||
|
self._parse_key = value
|
||||||
|
self.keys = set(self._parse_key(key) for key in self._raw_keys)
|
||||||
|
|
||||||
|
def __str__(self):
|
||||||
|
return self.text
|
||||||
|
|
||||||
|
|
||||||
class SelectOption:
|
class Select:
|
||||||
def __init__(self, options: List[Option] = None):
|
def __init__(
|
||||||
|
self,
|
||||||
|
options: List[Option] = None,
|
||||||
|
option_factory: Callable[[Any], Option] = None,
|
||||||
|
raw_options: List[Any] = None,
|
||||||
|
parse_option_key: Callable[[Any], Any] = lambda x: x,
|
||||||
|
ask_for_creating_option: Callable[[Option], bool] = lambda x: True,
|
||||||
|
**kwargs
|
||||||
|
):
|
||||||
|
self._parse_option_key: Callable[[Any], Any] = parse_option_key
|
||||||
|
self._ask_for_creating_option: Callable[[Option], bool] = ask_for_creating_option
|
||||||
|
|
||||||
self._key_to_option: Dict[Any, Option] = dict()
|
self._key_to_option: Dict[Any, Option] = dict()
|
||||||
self._options: List[Option] = options
|
self._options: List[Option] = []
|
||||||
|
|
||||||
self.extend(options or [])
|
options = options or []
|
||||||
|
self.option_factory: Optional[Callable[[Any], Option]] = option_factory
|
||||||
|
if self.can_create_options:
|
||||||
|
for raw_option in raw_options or []:
|
||||||
|
self.append(self.option_factory(raw_option))
|
||||||
|
elif raw_options is not None:
|
||||||
|
raise MKComposeException("Cannot create options without a factory.")
|
||||||
|
|
||||||
|
self.extend(options)
|
||||||
|
|
||||||
|
@property
|
||||||
|
def can_create_options(self) -> bool:
|
||||||
|
return self.option_factory is not None
|
||||||
|
|
||||||
def append(self, option: Option):
|
def append(self, option: Option):
|
||||||
|
option.parse_key = self._parse_option_key
|
||||||
self._options.append(option)
|
self._options.append(option)
|
||||||
for key in option.keys:
|
for key in option.keys:
|
||||||
self._key_to_option[key] = option
|
self._key_to_option[key] = option
|
||||||
@ -475,3 +527,32 @@ class SelectOption:
|
|||||||
def extend(self, options: List[Option]):
|
def extend(self, options: List[Option]):
|
||||||
for option in options:
|
for option in options:
|
||||||
self.append(option)
|
self.append(option)
|
||||||
|
|
||||||
|
def __iter__(self) -> Generator[Option, None, None]:
|
||||||
|
for option in self._options:
|
||||||
|
if option.hidden:
|
||||||
|
continue
|
||||||
|
|
||||||
|
yield option
|
||||||
|
|
||||||
|
def __contains__(self, key: Any) -> bool:
|
||||||
|
return key in self._key_to_option
|
||||||
|
|
||||||
|
def __getitem__(self, key: Any) -> Option:
|
||||||
|
return self._key_to_option[key]
|
||||||
|
|
||||||
|
def create_option(self, key: Any, **kwargs) -> Option:
|
||||||
|
if not self.can_create_options:
|
||||||
|
raise MKComposeException("Cannot create options without a factory.")
|
||||||
|
|
||||||
|
option = self.option_factory(key, **kwargs)
|
||||||
|
self.append(option)
|
||||||
|
return option
|
||||||
|
|
||||||
|
def choose(self, key: Any) -> Optional[Option]:
|
||||||
|
if key not in self:
|
||||||
|
if self.can_create_options and self._ask_for_creating_option(key):
|
||||||
|
return self.create_option(key)
|
||||||
|
return None
|
||||||
|
|
||||||
|
return self[key]
|
||||||
|
@ -1,8 +1,12 @@
|
|||||||
|
from __future__ import annotations
|
||||||
|
|
||||||
from dataclasses import dataclass
|
from dataclasses import dataclass
|
||||||
from typing import Dict, Generator, List, Tuple, Type, Union
|
from typing import TYPE_CHECKING, Dict, Generator, List, Tuple, Type, Union
|
||||||
|
|
||||||
from ..objects import DatabaseObject
|
from ..objects import DatabaseObject
|
||||||
from . import Page
|
|
||||||
|
if TYPE_CHECKING:
|
||||||
|
from . import Page
|
||||||
|
|
||||||
|
|
||||||
@dataclass
|
@dataclass
|
||||||
|
@ -1,26 +1,17 @@
|
|||||||
from typing import List, Optional, Type, Tuple
|
|
||||||
from urllib.parse import urlparse, urlunparse, parse_qs
|
|
||||||
from enum import Enum
|
from enum import Enum
|
||||||
import requests
|
from typing import List, Optional, Tuple, Type
|
||||||
|
from urllib.parse import parse_qs, urlparse, urlunparse
|
||||||
|
|
||||||
import python_sponsorblock
|
import python_sponsorblock
|
||||||
|
import requests
|
||||||
|
|
||||||
from ...objects import Source, DatabaseObject, Song, Target
|
|
||||||
from .._abstract import Page
|
|
||||||
from ...objects import (
|
|
||||||
Artist,
|
|
||||||
Source,
|
|
||||||
Song,
|
|
||||||
Album,
|
|
||||||
Label,
|
|
||||||
Target,
|
|
||||||
FormattedText,
|
|
||||||
ID3Timestamp
|
|
||||||
)
|
|
||||||
from ...connection import Connection
|
from ...connection import Connection
|
||||||
|
from ...download import Page
|
||||||
|
from ...objects import (Album, Artist, DatabaseObject, FormattedText,
|
||||||
|
ID3Timestamp, Label, Song, Source, Target)
|
||||||
|
from ...utils.config import logging_settings, main_settings, youtube_settings
|
||||||
|
from ...utils.enums import ALL_SOURCE_TYPES, SourceType
|
||||||
from ...utils.support_classes.download_result import DownloadResult
|
from ...utils.support_classes.download_result import DownloadResult
|
||||||
from ...utils.config import youtube_settings, logging_settings, main_settings
|
|
||||||
from ...utils.enums import SourceType, ALL_SOURCE_TYPES
|
|
||||||
|
|
||||||
|
|
||||||
def get_invidious_url(path: str = "", params: str = "", query: str = "", fragment: str = "") -> str:
|
def get_invidious_url(path: str = "", params: str = "", query: str = "", fragment: str = "") -> str:
|
||||||
|
@ -3,6 +3,9 @@ class MKBaseException(Exception):
|
|||||||
self.message = message
|
self.message = message
|
||||||
super().__init__(message, **kwargs)
|
super().__init__(message, **kwargs)
|
||||||
|
|
||||||
|
# Compose exceptions. Those usually mean a bug on my side.
|
||||||
|
class MKComposeException(MKBaseException):
|
||||||
|
pass
|
||||||
|
|
||||||
# Downloading
|
# Downloading
|
||||||
class MKDownloadException(MKBaseException):
|
class MKDownloadException(MKBaseException):
|
||||||
|
Loading…
Reference in New Issue
Block a user