diff --git a/src/music_kraken/objects/parents.py b/src/music_kraken/objects/parents.py index ab4eb2b..1c35742 100644 --- a/src/music_kraken/objects/parents.py +++ b/src/music_kraken/objects/parents.py @@ -28,7 +28,7 @@ class DatabaseObject: 64 bit integer, but this is defined in shared.py in ID_BITS the range is defined in the Tuple ID_RANGE """ - _id = random.randint(*main_settings['id_bits']) + _id = random.randint(0, main_settings['id_bits']) self.automatic_id = True LOGGER.debug(f"Id for {type(self).__name__} isn't set. Setting to {_id}") diff --git a/src/music_kraken/objects/target.py b/src/music_kraken/objects/target.py index c84ebe3..94cb2d8 100644 --- a/src/music_kraken/objects/target.py +++ b/src/music_kraken/objects/target.py @@ -6,7 +6,7 @@ import requests from tqdm import tqdm from .parents import DatabaseObject -from ..utils import shared +from ..utils.config import main_settings, logging_settings LOGGER = logging.getLogger("target") @@ -36,7 +36,7 @@ class Target(DatabaseObject): ) -> None: super().__init__(dynamic=dynamic) self._file: Path = Path(file) - self._path: Path = Path(shared.MUSIC_DIR, path) if relative_to_music_dir else Path(path) + self._path: Path = Path(main_settings["music_directory"], path) if relative_to_music_dir else Path(path) self.is_relative_to_music_dir: bool = relative_to_music_dir @@ -95,13 +95,13 @@ class Target(DatabaseObject): """ with tqdm(total=total_size, unit='B', unit_scale=True, unit_divisor=1024, desc=desc) as t: - for chunk in r.iter_content(chunk_size=shared.CHUNK_SIZE): + for chunk in r.iter_content(chunk_size=main_settings["chunk_size"]): size = f.write(chunk) t.update(size) return True except requests.exceptions.Timeout: - shared.DOWNLOAD_LOGGER.error("Stream timed out.") + logging_settings["download_logger"].error("Stream timed out.") return False def open(self, file_mode: str, **kwargs) -> TextIO: diff --git a/src/music_kraken/pages/abstract.py b/src/music_kraken/pages/abstract.py index 4a24ae7..babd08c 100644 --- a/src/music_kraken/pages/abstract.py +++ b/src/music_kraken/pages/abstract.py @@ -22,7 +22,6 @@ from ..objects import ( from ..utils.enums.source import SourcePages from ..utils.enums.album import AlbumType from ..audio import write_metadata_to_target, correct_codec -from ..utils import shared from ..utils.config import main_settings from ..utils.support_classes import Query, DownloadResult @@ -352,7 +351,7 @@ class Page: if self.NO_ADDITIONAL_DATA_FROM_SONG: skip_next_details = True - if not download_all and music_object.album_type in shared.ALBUM_TYPE_BLACKLIST: + if not download_all and music_object.album_type.value in main_settings["album_type_blacklist"]: return DownloadResult() if not isinstance(music_object, Song) or not self.NO_ADDITIONAL_DATA_FROM_SONG: @@ -398,7 +397,7 @@ class Page: return DownloadResult(error_message=f"No source found for {song.title} as {self.__class__.__name__}.") temp_target: Target = Target( - path=shared.TEMP_DIR, + path=main_settings["temp_directory"], file=str(random.randint(0, 999999)) ) diff --git a/src/music_kraken/pages/youtube_music/youtube_music.py b/src/music_kraken/pages/youtube_music/youtube_music.py index 7e03670..6b50edf 100644 --- a/src/music_kraken/pages/youtube_music/youtube_music.py +++ b/src/music_kraken/pages/youtube_music/youtube_music.py @@ -89,7 +89,7 @@ class YouTubeMusicCredentials: # the context in requests context: dict - + class YoutubeMusic(SuperYouTube): # CHANGE @@ -101,57 +101,7 @@ class YoutubeMusic(SuperYouTube): self.credentials: YouTubeMusicCredentials = YouTubeMusicCredentials( api_key=youtube_settings["youtube_music_api_key"], ctoken="", - context= { - "client": { - "hl": "en", - "gl": "DE", - "remoteHost": "87.123.241.77", - "deviceMake": "", - "deviceModel": "", - "visitorData": "CgtiTUxaTHpoXzk1Zyia59WlBg%3D%3D", - "userAgent": self.connection.user_agent, - "clientName": "WEB_REMIX", - "clientVersion": "1.20230710.01.00", - "osName": "X11", - "osVersion": "", - "originalUrl": "https://music.youtube.com/", - "platform": "DESKTOP", - "clientFormFactor": "UNKNOWN_FORM_FACTOR", - "configInfo": { - "appInstallData": "", - "coldConfigData": "", - "coldHashData": "", - "hotHashData": "" - }, - "userInterfaceTheme": "USER_INTERFACE_THEME_DARK", - "timeZone": "Atlantic/Jan_Mayen", - "browserName": "Firefox", - "browserVersion": "115.0", - "acceptHeader": "text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,*/*;q=0.8", - "deviceExperimentId": "ChxOekkxTmpnek16UTRNVFl4TkRrek1ETTVOdz09EJrn1aUGGJrn1aUG", - "screenWidthPoints": 584, - "screenHeightPoints": 939, - "screenPixelDensity": 1, - "screenDensityFloat": 1, - "utcOffsetMinutes": 120, - "musicAppInfo": { - "pwaInstallabilityStatus": "PWA_INSTALLABILITY_STATUS_UNKNOWN", - "webDisplayMode": "WEB_DISPLAY_MODE_BROWSER", - "storeDigitalGoodsApiSupportStatus": { - "playStoreDigitalGoodsApiSupportStatus": "DIGITAL_GOODS_API_SUPPORT_STATUS_UNSUPPORTED" - } - } - }, - "user": { "lockedSafetyMode": False }, - "request": { - "useSsl": True, - "internalExperimentFlags": [], - "consistencyTokenJars": [] - }, - "adSignalsInfo": { - "params": [] - } - } + context=youtube_settings["youtube_music_innertube_context"] ) self.start_millis = get_current_millis() @@ -207,12 +157,12 @@ class YoutubeMusic(SuperYouTube): found_context = False for context_string in re.findall(context_pattern, content): try: - context = json.loads("{" + context_string + "}") + youtube_settings["youtube_music_innertube_context"] = json.loads("{" + context_string + "}") found_context except json.decoder.JSONDecodeError: continue - self.credentials.context = context + self.credentials.context = youtube_settings["youtube_music_innertube_context"] break if not found_context: diff --git a/src/music_kraken/utils/config/attributes/attribute.py b/src/music_kraken/utils/config/attributes/attribute.py index e8e87db..1d08643 100644 --- a/src/music_kraken/utils/config/attributes/attribute.py +++ b/src/music_kraken/utils/config/attributes/attribute.py @@ -57,9 +57,16 @@ class Attribute: self.name = name self.raw_data = {name: default_value} - self.value = default_value + self.value = None self.description: Optional[str] = description + self.loaded_settings: dict = None + + def initialize_from_config(self, loaded_settings: dict): + self.loaded_settings = loaded_settings + + if not self.load_toml(self.raw_data): + logging.warning(f"Couldn't load the initial value of {self.name}: {self.raw_data[self.name]}") def unparse_simple_value(self, value: any) -> any: return value @@ -81,28 +88,27 @@ class Attribute: return callback(__object) - def load_toml(self, loaded_toml: dict, loaded_settings: dict) -> bool: + def load_toml(self, loaded_toml: dict) -> bool: """ returns true if succesfull """ if self.name not in loaded_toml: LOGGER.warning(f"No setting by the name {self.name} found in the settings file.") - loaded_settings[self.name] = self.value + self.loaded_settings.__setitem__(self.name, self.value, True) return self.raw_data = loaded_toml[self.name] _object = deepcopy(loaded_toml[self.name]) try: - self._recursive_parse_object(_object, self.parse_simple_value) + parsed_object = self._recursive_parse_object(_object, self.parse_simple_value) except SettingValueError as settings_error: logging.warning(settings_error) return False - self.value = _object - - loaded_settings[self.name] = self.value + self.value = parsed_object + self.loaded_settings.__setitem__(self.name, self.value, True) return True diff --git a/src/music_kraken/utils/config/config.py b/src/music_kraken/utils/config/config.py index c822bd0..fff26ff 100644 --- a/src/music_kraken/utils/config/config.py +++ b/src/music_kraken/utils/config/config.py @@ -16,12 +16,15 @@ class ConfigDict(dict): def __getattribute__(self, __name: str) -> Any: return super().__getattribute__(__name) - def __setitem__(self, __key: Any, __value: Any) -> None: - attribute: Attribute = self.config_reference.attribute_map[__key] - attribute.load_toml({attribute.name: __value}) - self.config_reference.write() + def __setitem__(self, __key: Any, __value: Any, from_attribute: bool = False) -> None: + if not from_attribute: + attribute: Attribute = self.config_reference.attribute_map[__key] + attribute.load_toml({attribute.name: __value}) + self.config_reference.write() - return super().__setitem__(__key, attribute.value) + __value = attribute.value + + return super().__setitem__(__key, __value) class Config: @@ -29,15 +32,15 @@ class Config: self.config_file: Path = config_file self.component_list: Tuple[Union[Attribute, Description, EmptyLine]] = componet_list - self.loaded_settings: dict = {} + self.loaded_settings: ConfigDict = ConfigDict(self) self.attribute_map = {} for component in self.component_list: if not isinstance(component, Attribute): continue + component.initialize_from_config(self.loaded_settings) self.attribute_map[component.name] = component - self.loaded_settings[component.name] = component.value @property def toml_string(self): @@ -59,4 +62,4 @@ class Config: for component in self.component_list: if isinstance(component, Attribute): - component.load_toml(toml_data, self.loaded_settings) + component.load_toml(toml_data) diff --git a/src/music_kraken/utils/config/config_files/youtube_config.py b/src/music_kraken/utils/config/config_files/youtube_config.py index 245f21e..da1d12b 100644 --- a/src/music_kraken/utils/config/config_files/youtube_config.py +++ b/src/music_kraken/utils/config/config_files/youtube_config.py @@ -30,7 +30,59 @@ Dw. if it is empty, Rachel will fetch it automatically for you <333 "https://www.youtu.be/" ], description="""This is used to detect, if an url is from youtube, or any alternativ frontend. If any instance seems to be missing, run music kraken with the -f flag."""), - Attribute(name="use_sponsor_block", default_value=True, description="Use sponsor block to remove adds or simmilar from the youtube videos.") + Attribute(name="use_sponsor_block", default_value=True, description="Use sponsor block to remove adds or simmilar from the youtube videos."), + + Attribute(name="youtube_music_innertube_context", default_value={ + "client": { + "hl": "en", + "gl": "DE", + "remoteHost": "87.123.241.77", + "deviceMake": "", + "deviceModel": "", + "visitorData": "CgtiTUxaTHpoXzk1Zyia59WlBg%3D%3D", + "userAgent": "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/116.0.0.0 Safari/537.36", + "clientName": "WEB_REMIX", + "clientVersion": "1.20230710.01.00", + "osName": "X11", + "osVersion": "", + "originalUrl": "https://music.youtube.com/", + "platform": "DESKTOP", + "clientFormFactor": "UNKNOWN_FORM_FACTOR", + "configInfo": { + "appInstallData": "", + "coldConfigData": "", + "coldHashData": "", + "hotHashData": "" + }, + "userInterfaceTheme": "USER_INTERFACE_THEME_DARK", + "timeZone": "Atlantic/Jan_Mayen", + "browserName": "Firefox", + "browserVersion": "115.0", + "acceptHeader": "text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,*/*;q=0.8", + "deviceExperimentId": "ChxOekkxTmpnek16UTRNVFl4TkRrek1ETTVOdz09EJrn1aUGGJrn1aUG", + "screenWidthPoints": 584, + "screenHeightPoints": 939, + "screenPixelDensity": 1, + "screenDensityFloat": 1, + "utcOffsetMinutes": 120, + "musicAppInfo": { + "pwaInstallabilityStatus": "PWA_INSTALLABILITY_STATUS_UNKNOWN", + "webDisplayMode": "WEB_DISPLAY_MODE_BROWSER", + "storeDigitalGoodsApiSupportStatus": { + "playStoreDigitalGoodsApiSupportStatus": "DIGITAL_GOODS_API_SUPPORT_STATUS_UNSUPPORTED" + } + } + }, + "user": { "lockedSafetyMode": False }, + "request": { + "useSsl": True, + "internalExperimentFlags": [], + "consistencyTokenJars": [] + }, + "adSignalsInfo": { + "params": [] + } + }, description="Don't bother about this. It is something technical, but if you wanna change the innertube requests... go on.") ], LOCATIONS.get_config_file("youtube")) @@ -43,3 +95,4 @@ class SettingsStructure(TypedDict): youtube_music_clean_data: bool youtube_url: List[ParseResult] use_sponsor_block: bool + youtube_music_innertube_context: dict