feat: fixed bugs

This commit is contained in:
Hellow 2023-12-19 22:11:46 +01:00
parent 22b32b0c50
commit a2a2297354
13 changed files with 174 additions and 485 deletions

View File

@ -1,5 +1,6 @@
<component name="InspectionProjectProfileManager">
<settings>
<option name="PROJECT_PROFILE" value="Default" />
<option name="USE_PROJECT_PROFILE" value="false" />
<version value="1.0" />
</settings>

View File

@ -4,4 +4,7 @@
<option name="sdkName" value="Python 3.10 (music-downloader)" />
</component>
<component name="ProjectRootManager" version="2" project-jdk-name="Python 3.10 (music-downloader)" project-jdk-type="Python SDK" />
<component name="PythonCompatibilityInspectionAdvertiser">
<option name="version" value="3" />
</component>
</project>

View File

@ -25,7 +25,6 @@ print(other_song.__dict__)
print(song)
"""
only_smile = Artist(
name="Only Smile",
source_list=[Source(SourcePages.BANDCAMP, "https://onlysmile.bandcamp.com/")],
@ -126,7 +125,6 @@ for _id, _object in objects_by_id.items():
print(only_smile)
"""
"""
c = Collection([Song(title="hi"), Song(title="hi2"), Song(title="hi3")])
c1 = Collection([Song(title="he"), Song(title="hi5")])
c11 = Collection([Song(title="wow how ultra subby", isrc="hiii")])

View File

@ -1,5 +1,5 @@
from typing_extensions import TypeVar
from .option import Options
from .parents import DatabaseObject
from .metadata import Metadata, Mapping as ID3Mapping, ID3Timestamp
@ -19,3 +19,5 @@ from .collection import Collection
from .country import Country
from .contact import Contact
from .parents import OuterProxy as DatabaseObject

View File

@ -54,6 +54,7 @@ class Collection(Generic[T]):
self._indexed_values[name].add(value)
self._indexed_to_objects[value].append(__object)
print(from_map)
if not from_map:
for attribute, new_object in self.contain_given_in_attribute.items():
__object.__getattribute__(attribute).contain_collection_inside(new_object)
@ -143,6 +144,7 @@ class Collection(Generic[T]):
2. merge into existing object
3. remap existing object
"""
self = self.__self__
if __object.id in self._contains_ids:
return
@ -233,7 +235,7 @@ class Collection(Generic[T]):
# now the ugly part
# replace all refs of the other element with this one
self._risky_merge(equal_collection)
self = self._risky_merge(equal_collection)
def contain_collection_inside(self, sub_collection: "Collection"):
"""
@ -253,6 +255,10 @@ class Collection(Generic[T]):
def __len__(self) -> int:
return len(self._data) + sum(len(collection) for collection in self.children)
@property
def empty(self) -> bool:
return self.__len__() == 0
def __iter__(self) -> Iterator[T]:
for element in self._data:
yield element

View File

@ -1,10 +1,10 @@
from typing import Optional, List, Tuple
from ..utils.enums.contact import ContactMethod
from .parents import DatabaseObject
from .parents import OuterProxy
class Contact(DatabaseObject):
class Contact(OuterProxy):
COLLECTION_STRING_ATTRIBUTES = tuple()
SIMPLE_STRING_ATTRIBUTES = {
"contact_method": None,
@ -18,7 +18,8 @@ class Contact(DatabaseObject):
('value', self.value),
]
def __init__(self, contact_method: ContactMethod, value: str) -> None:
def __init__(self, contact_method: ContactMethod, value: str, **kwargs) -> None:
super().__init__(**kwargs)
self.contact_method: ContactMethod = contact_method
self.value: str = value

View File

@ -72,7 +72,6 @@ class Language:
alpha_2: str
alpha_3: str
name: str
numeric: int
@classmethod
def by_pycountry(cls, language) -> Language:
@ -82,12 +81,11 @@ class Language:
alpha_2=alpha_2,
alpha_3=language.alpha_3,
name=language.name,
numeric=language.numeric,
)
@classmethod
def by_alpha_2(cls, alpha_2: str) -> Language:
return cls.by_pycountry(pycountry.languages.get(alpha_2=alpha_2))
return cls.by_pycountry(pycountry.languages.get(alpha_2=alpha_2.upper()))
@classmethod
def by_alpha_3(cls, alpha_3: str) -> Language:

View File

@ -2,12 +2,12 @@ from typing import List
from collections import defaultdict
import pycountry
from .parents import DatabaseObject
from .parents import OuterProxy
from .source import Source, SourceCollection
from .formatted_text import FormattedText
class Lyrics(DatabaseObject):
class Lyrics(OuterProxy):
COLLECTION_STRING_ATTRIBUTES = ("source_collection",)
SIMPLE_STRING_ATTRIBUTES = {
"text": FormattedText(),
@ -23,7 +23,7 @@ class Lyrics(DatabaseObject):
source_list: List[Source] = None,
**kwargs
) -> None:
DatabaseObject.__init__(self, _id=_id, dynamic=dynamic, **kwargs)
super().__init__(_id=_id, dynamic=dynamic, **kwargs)
self.text: FormattedText = text or FormattedText()
self.language: pycountry.Languages = language

View File

@ -1,31 +1,17 @@
from __future__ import annotations
import random
from collections import defaultdict
from typing import Optional, Dict, Tuple, List, Type, Generic, TypeVar, Any
from dataclasses import dataclass
from typing import Optional, Dict, Tuple, List, Type, Generic, Any, TypeVar
from .metadata import Metadata
from .option import Options
from ..utils.config import logging_settings
from ..utils.shared import HIGHEST_ID
from ..utils.config import main_settings, logging_settings
from ..utils.support_classes.hacking import MetaClass
from ..utils.exception.objects import IsDynamicException
LOGGER = logging_settings["object_logger"]
P = TypeVar('P')
@dataclass
class StaticAttribute(Generic[P]):
name: str
default_value: Any = None
weight: float = 0
is_collection: bool = False
is_downwards_collection: bool = False
is_upwards_collection: bool = False
P = TypeVar("P", bound="OuterProxy")
class InnerData:
@ -68,13 +54,43 @@ class InnerData:
self.__setattr__(key, value)
class Meta(type):
def __new__(meta, classname, bases, classDict):
for key, value in classDict.items():
if (not key.islower()) or key.startswith("_") or (key.startswith("__") and key.endswith("__")):
continue
class OuterProxy:
if hasattr(value, "__call__") or isinstance(value, property) or isinstance(value, classmethod):
continue
print("hi", type(value))
print(key, value)
new_instance = type.__new__(meta, classname, bases, classDict)
return new_instance
class OuterProxy(metaclass=Meta):
"""
Wraps the inner data, and provides apis, to naturally access those values.
"""
_default_factories: dict
_default_factories: dict = {}
def __new__(cls, *args, **kwargs):
for key, value in cls.__dict__["__annotations__"].items():
if (not key.islower()) or key.startswith("_") or (key.startswith("__") and key.endswith("__")):
continue
if key in cls._default_factories:
continue
cls._default_factories[key] = lambda: None
return super().__new__(cls)
def __init__(self, _id: int = None, dynamic: bool = False, **kwargs):
_automatic_id: bool = False
@ -91,6 +107,17 @@ class OuterProxy:
kwargs["id"] = _id
kwargs["dynamic"] = dynamic
key: str
for key, value in super().__getattribute__("__dict__").items():
if (not key.islower()) or key.startswith("_") or (key.startswith("__") and key.endswith("__")):
continue
if hasattr(value, "__call__") or isinstance(value, property) or isinstance(value, classmethod):
continue
print(type(value))
print(key, value)
for name, factory in type(self)._default_factories.items():
if name not in kwargs:
kwargs[name] = factory()
@ -160,222 +187,32 @@ class OuterProxy:
self._inner.__merge__(__other._inner, override=override)
__other._inner = self._inner
class Attribute(Generic[P]):
def __init__(self, database_object: "DatabaseObject", static_attribute: StaticAttribute) -> None:
self.database_object: DatabaseObject = database_object
self.static_attribute: StaticAttribute = static_attribute
@property
def name(self) -> str:
return self.static_attribute.name
def get(self) -> P:
return self.database_object.__getattribute__(self.name)
def set(self, value: P):
self.database_object.__setattr__(self.name, value)
class DatabaseObject(metaclass=MetaClass):
COLLECTION_STRING_ATTRIBUTES: tuple = tuple()
SIMPLE_STRING_ATTRIBUTES: dict = dict()
# contains all collection attributes, which describe something "smaller"
# e.g. album has songs, but not artist.
DOWNWARDS_COLLECTION_STRING_ATTRIBUTES: tuple = tuple()
UPWARDS_COLLECTION_STRING_ATTRIBUTES: tuple = tuple()
STATIC_ATTRIBUTES: List[StaticAttribute] = list()
def __init__(self, _id: int = None, dynamic: bool = False, **kwargs) -> None:
self.automatic_id: bool = False
if _id is None and not dynamic:
def metadata(self) -> Metadata:
"""
generates a random integer id
64 bit integer, but this is defined in shared.py in ID_BITS
the range is defined in the Tuple ID_RANGE
This is an interface.
:return:
"""
_id = random.randint(0, HIGHEST_ID)
self.automatic_id = True
# LOGGER.debug(f"Id for {type(self).__name__} isn't set. Setting to {_id}")
self._attributes: List[Attribute] = []
self._simple_attribute_list: List[Attribute] = []
self._collection_attributes: List[Attribute] = []
self._downwards_collection_attributes: List[Attribute] = []
self._upwards_collection_attributes: List[Attribute] = []
for static_attribute in self.STATIC_ATTRIBUTES:
attribute: Attribute = Attribute(self, static_attribute)
self._attributes.append(attribute)
if static_attribute.is_collection:
if static_attribute.is_collection:
self._collection_attributes.append(attribute)
if static_attribute.is_upwards_collection:
self._upwards_collection_attributes.append(attribute)
if static_attribute.is_downwards_collection:
self._downwards_collection_attributes.append(attribute)
else:
self._simple_attribute_list.append(attribute)
# The id can only be None, if the object is dynamic (self.dynamic = True)
self.id: Optional[int] = _id
self.dynamic = dynamic
self.build_version = -1
super().__init__()
return Metadata()
@property
def upwards_collection(self) -> Collection:
for attribute in self._upwards_collection_attributes:
yield attribute.get()
@property
def downwards_collection(self) -> Collection:
for attribute in self._downwards_collection_attributes:
yield attribute.get()
@property
def all_collections(self) -> Collection:
for attribute in self._collection_attributes:
yield attribute.get()
def __hash__(self):
if self.dynamic:
raise TypeError("Dynamic DatabaseObjects are unhashable.")
return self.id
def __deep_eq__(self, other) -> bool:
if not isinstance(other, type(self)):
return False
return super().__eq__(other)
def __eq__(self, other) -> bool:
if not isinstance(other, type(self)):
return False
if super().__eq__(other):
return True
# add the checks for dynamic, to not throw an exception
if not self.dynamic and not other.dynamic and self.id == other.id:
return True
temp_attribute_map: Dict[str, set] = defaultdict(set)
# building map with sets
for name, value in self.indexing_values:
temp_attribute_map[name].add(value)
# check against the attributes of the other object
for name, other_value in other.indexing_values:
if other_value in temp_attribute_map[name]:
return True
return False
def options(self) -> List[P]:
return [self]
@property
def indexing_values(self) -> List[Tuple[str, object]]:
"""
returns a map of the name and values of the attributes.
This helps in comparing classes for equal data (eg. being the same song but different attributes)
This is an interface.
It is supposed to return a map of the name and values for all important attributes.
This helps in comparing classes for equal data (e.g. being the same song but different attributes)
TODO
Rewrite this approach into a approach, that is centered around statistics, and not binaries.
Instead of: one of this matches, it is the same
This: If enough attributes are similar enough, they are the same
Returns:
List[Tuple[str, object]]: the first element in the tuple is the name of the attribute, the second the value.
"""
return list()
def merge(self, other, override: bool = False, replace_all_refs: bool = False):
print("merge")
if other is None:
return
if self.__deep_eq__(other):
return
if not isinstance(other, type(self)):
LOGGER.warning(f"can't merge \"{type(other)}\" into \"{type(self)}\"")
return
for collection in self._collection_attributes:
if hasattr(self, collection.name) and hasattr(other, collection.name):
if collection.get() is not getattr(other, collection.name):
pass
collection.get().extend(getattr(other, collection.name))
for simple_attribute, default_value in type(self).SIMPLE_STRING_ATTRIBUTES.items():
if getattr(other, simple_attribute) == default_value:
continue
if override or getattr(self, simple_attribute) == default_value:
setattr(self, simple_attribute, getattr(other, simple_attribute))
if replace_all_refs:
self._risky_merge(other)
def strip_details(self):
for collection in type(self).DOWNWARDS_COLLECTION_STRING_ATTRIBUTES:
getattr(self, collection).clear()
@property
def metadata(self) -> Metadata:
return Metadata()
@property
def options(self) -> List["DatabaseObject"]:
return [self]
@property
def option_string(self) -> str:
return self.__repr__()
def _build_recursive_structures(self, build_version: int, merge: False):
pass
def compile(self, merge_into: bool = False):
"""
compiles the recursive structures,
and does depending on the object some other stuff.
no need to override if only the recursive structure should be build.
override self.build_recursive_structures() instead
"""
self._build_recursive_structures(build_version=random.randint(0, 99999), merge=merge_into)
def _add_other_db_objects(self, object_type: Type["DatabaseObject"], object_list: List["DatabaseObject"]):
pass
def add_list_of_other_objects(self, object_list: List["DatabaseObject"]):
d: Dict[Type[DatabaseObject], List[DatabaseObject]] = defaultdict(list)
for db_object in object_list:
d[type(db_object)].append(db_object)
for key, value in d.items():
self._add_other_db_objects(key, value)
class MainObject(DatabaseObject):
"""
This is the parent class for all "main" data objects:
- Song
- Album
- Artist
- Label
It has all the functionality of the "DatabaseObject" (it inherits from said class)
but also some added functions as well.
"""
def __init__(self, _id: int = None, dynamic: bool = False, **kwargs):
DatabaseObject.__init__(self, _id=_id, dynamic=dynamic, **kwargs)
self.additional_arguments: dict = kwargs
return []

View File

@ -2,7 +2,7 @@ from __future__ import annotations
import random
from collections import defaultdict
from typing import List, Optional, Dict, Tuple, Type
from typing import List, Optional, Dict, Tuple, Type, Union
import pycountry
@ -17,7 +17,7 @@ from .metadata import (
Metadata
)
from .option import Options
from .parents import DatabaseObject, StaticAttribute
from .parents import OuterProxy, P
from .source import Source, SourceCollection
from .target import Target
from .country import Language, Country
@ -59,7 +59,7 @@ class Song(Base):
"main_artist_collection": Collection,
"album_collection": Collection,
"feature_artist_collection": Collection
"feature_artist_collection": Collection,
}
"""
@ -161,14 +161,10 @@ class Song(Base):
f"by Artist({OPTION_STRING_DELIMITER.join(artist.name for artist in self.main_artist_collection)}) " \
f"feat. Artist({OPTION_STRING_DELIMITER.join(artist.name for artist in self.feature_artist_collection)})"
@property
def options(self) -> List[DatabaseObject]:
"""
Return a list of related objects including the song object, album object, main artist objects, and
feature artist objects.
:return: a list of objects that are related to the Song object
"""
@property
def options(self) -> List[P]:
options = self.main_artist_collection.shallow_list
options.extend(self.feature_artist_collection)
options.extend(self.album_collection)
@ -226,6 +222,11 @@ class Album(Base):
"language": lambda: Language.by_alpha_2("en"),
"date": ID3Timestamp,
"notes": FormattedText,
"source_collection": SourceCollection,
"artist_collection": Collection,
"song_collection": Collection,
"label_collection": Collection,
}
DOWNWARDS_COLLECTION_STRING_ATTRIBUTES = ("song_collection", )
@ -236,42 +237,6 @@ class Album(Base):
"main_artist_collection": self.artist_collection
}
def _build_recursive_structures(self, build_version: int, merge: bool):
if build_version == self.build_version:
return
self.build_version = build_version
song: Song
for song in self.song_collection:
song.album_collection.append(self, merge_on_conflict=merge, merge_into_existing=False)
song._build_recursive_structures(build_version=build_version, merge=merge)
artist: Artist
for artist in self.artist_collection:
artist.main_album_collection.append(self, merge_on_conflict=merge, merge_into_existing=False)
artist._build_recursive_structures(build_version=build_version, merge=merge)
label: Label
for label in self.label_collection:
label.album_collection.append(self, merge_on_conflict=merge, merge_into_existing=False)
label._build_recursive_structures(build_version=build_version, merge=merge)
def _add_other_db_objects(self, object_type: Type["DatabaseObject"], object_list: List["DatabaseObject"]):
if object_type is Song:
self.song_collection.extend(object_list)
return
if object_type is Artist:
self.artist_collection.extend(object_list)
return
if object_type is Album:
return
if object_type is Label:
self.label_collection.extend(object_list)
return
@property
def indexing_values(self) -> List[Tuple[str, object]]:
return [
@ -311,7 +276,7 @@ class Album(Base):
f"under Label({OPTION_STRING_DELIMITER.join([label.name for label in self.label_collection])})"
@property
def options(self) -> List[DatabaseObject]:
def options(self) -> List[P]:
options = self.artist_collection.shallow_list
options.append(self)
options.extend(self.song_collection)
@ -434,122 +399,50 @@ class Artist(Base):
"unformated_location": None,
}
name: str
unified_name: str
country: Country
formed_in: ID3Timestamp
notes: FormattedText
lyrical_themes: List[str]
general_genre: str
unformated_location: str
source_collection: SourceCollection
contact_collection: Collection[Contact]
feature_song_collection: Collection[Song]
main_album_collection: Collection[Album]
label_collection: Collection[Label]
_default_factories = {
"formed_in": ID3Timestamp,
"notes": FormattedText,
"lyrical_themes": list,
"general_genre": lambda: "",
"source_collection": SourceCollection,
"feature_song_collection": Collection,
"main_album_collection": Collection,
"contact_collection": Collection,
"label_collection": Collection,
}
DOWNWARDS_COLLECTION_STRING_ATTRIBUTES = ("feature_song_collection", "main_album_collection")
UPWARDS_COLLECTION_STRING_ATTRIBUTES = ("label_collection", )
STATIC_ATTRIBUTES = [
StaticAttribute(name="name", weight=.5),
StaticAttribute(name="unified_name", weight=.3),
StaticAttribute(name="country"),
StaticAttribute(name="formed_in", default_value=ID3Timestamp()),
StaticAttribute(name="lyrical_themes", default_value=[]),
StaticAttribute(name="general_genre", default_value=""),
StaticAttribute(name="notes", default_value=FormattedText()),
StaticAttribute(name="unformated_location"),
StaticAttribute(name="source_collection", is_collection=True),
StaticAttribute(name="contact_collection", is_collection=True),
StaticAttribute(name="feature_song_collection", is_collection=True, is_downwards_collection=True),
StaticAttribute(name="main_album_collection", is_collection=True, is_downwards_collection=True),
StaticAttribute(name="label_collection", is_collection=True, is_upwards_collection=True),
]
def __init__(
self,
_id: int = None,
dynamic: bool = False,
name: str = None,
unified_name: str = None,
source_list: List[Source] = None,
feature_song_list: List[Song] = None,
main_album_list: List[Album] = None,
contact_list: List[Contact] = None,
notes: FormattedText = None,
lyrical_themes: List[str] = None,
general_genre: str = "",
country: CountryTyping = None,
formed_in: ID3Timestamp = None,
label_list: List['Label'] = None,
unformated_location: str = None,
**kwargs
):
Base.__init__(self, _id=_id, dynamic=dynamic, **kwargs)
self.name: str = name
self.unified_name: str = unified_name
if unified_name is None and name is not None:
self.unified_name = unify(name)
"""
TODO implement album type and notes
"""
self.country: CountryTyping = country
self.formed_in: ID3Timestamp = formed_in
"""
notes, general genre, lyrics themes are attributes
which are meant to only use in outputs to describe the object
i mean do as you want but there is no strict rule about em so good luck
"""
self.notes: FormattedText = notes or FormattedText()
self.lyrical_themes: List[str] = lyrical_themes or []
self.general_genre = general_genre
self.unformated_location: Optional[str] = unformated_location
self.source_collection: SourceCollection = SourceCollection(source_list)
self.contact_collection: Collection[Label] = Collection(data=contact_list)
self.feature_song_collection: Collection[Song] = Collection(
data=feature_song_list,
append_object_to_attribute={
def __init_collections__(self):
self.feature_song_collection.append_object_to_attribute = {
"feature_artist_collection": self
}
)
self.main_album_collection: Collection[Album] = Collection(
data=main_album_list,
append_object_to_attribute={
self.main_album_collection.append_object_to_attribute = {
"artist_collection": self
}
)
self.label_collection: Collection[Label] = Collection(
data=label_list,
append_object_to_attribute={
self.label_collection.append_object_to_attribute = {
"current_artist_collection": self
}
)
def _add_other_db_objects(self, object_type: Type["DatabaseObject"], object_list: List["DatabaseObject"]):
if object_type is Song:
# this doesn't really make sense
# self.feature_song_collection.extend(object_list)
return
if object_type is Artist:
return
if object_type is Album:
self.main_album_collection.extend(object_list)
return
if object_type is Label:
self.label_collection.extend(object_list)
return
def compile(self, merge_into: bool = False):
"""
compiles the recursive structures,
and does depending on the object some other stuff.
no need to override if only the recursive structure should be built.
override self.build_recursive_structures() instead
"""
self.update_albumsort()
self._build_recursive_structures(build_version=random.randint(0, 99999), merge=merge_into)
def update_albumsort(self):
"""
@ -564,7 +457,7 @@ class Artist(Base):
if len(self.main_album_collection) <= 0:
return
type_section: Dict[AlbumType] = defaultdict(lambda: 2, {
type_section: Dict[AlbumType, int] = defaultdict(lambda: 2, {
AlbumType.OTHER: 0, # if I don't know it, I add it to the first section
AlbumType.STUDIO_ALBUM: 0,
AlbumType.EP: 0,
@ -608,27 +501,6 @@ class Artist(Base):
# replace the old collection with the new one
self.main_album_collection: Collection = Collection(data=album_list, element_type=Album)
def _build_recursive_structures(self, build_version: int, merge: False):
if build_version == self.build_version:
return
self.build_version = build_version
song: Song
for song in self.feature_song_collection:
song.feature_artist_collection.append(self, merge_on_conflict=merge, merge_into_existing=False)
song._build_recursive_structures(build_version=build_version, merge=merge)
album: Album
for album in self.main_album_collection:
album.artist_collection.append(self, merge_on_conflict=merge, merge_into_existing=False)
album._build_recursive_structures(build_version=build_version, merge=merge)
label: Label
for label in self.label_collection:
label.current_artist_collection.append(self, merge_on_conflict=merge, merge_into_existing=False)
label._build_recursive_structures(build_version=build_version, merge=merge)
@property
def indexing_values(self) -> List[Tuple[str, object]]:
return [
@ -664,16 +536,12 @@ class Artist(Base):
f"under Label({OPTION_STRING_DELIMITER.join([label.name for label in self.label_collection])})"
@property
def options(self) -> List[DatabaseObject]:
def options(self) -> List[P]:
options = [self]
options.extend(self.main_album_collection)
options.extend(self.feature_song_collection)
return options
@property
def country_string(self):
return self.country.alpha_3
@property
def feature_album(self) -> Album:
return Album(
@ -712,22 +580,27 @@ Label
class Label(Base):
COLLECTION_STRING_ATTRIBUTES = ("album_collection", "current_artist_collection")
SIMPLE_STRING_ATTRIBUTES = {
"name": None,
"unified_name": None,
"notes": FormattedText()
}
DOWNWARDS_COLLECTION_STRING_ATTRIBUTES = COLLECTION_STRING_ATTRIBUTES
STATIC_ATTRIBUTES = [
StaticAttribute(name="name", weight=.5),
StaticAttribute(name="unified_name", weight=.3),
StaticAttribute(name="notes", default_value=FormattedText()),
name: str
unified_name: str
notes: FormattedText
StaticAttribute(name="album_collection", is_collection=True, is_downwards_collection=True),
StaticAttribute(name="current_artist_collection", is_collection=True, is_downwards_collection=True),
]
source_collection: SourceCollection
contact_collection: Collection[Contact]
album_collection: Collection[Album]
current_artist_collection: Collection[Artist]
_default_factories = {
"notes": FormattedText,
"album_collection": Collection,
"current_artist_collection": Collection,
"source_collection": SourceCollection,
"contact_collection": Collection
}
def __init__(
self,
@ -753,33 +626,6 @@ class Label(Base):
self.album_collection: Collection[Album] = Collection(data=album_list, element_type=Album)
self.current_artist_collection: Collection[Artist] = Collection(data=current_artist_list, element_type=Artist)
def _add_other_db_objects(self, object_type: Type["DatabaseObject"], object_list: List["DatabaseObject"]):
if object_type is Song:
return
if object_type is Artist:
self.current_artist_collection.extend(object_list)
return
if object_type is Album:
self.album_collection.extend(object_list)
return
def _build_recursive_structures(self, build_version: int, merge: False):
if build_version == self.build_version:
return
self.build_version = build_version
album: Album
for album in self.album_collection:
album.label_collection.append(self, merge_on_conflict=merge, merge_into_existing=False)
album._build_recursive_structures(build_version=build_version, merge=merge)
artist: Artist
for artist in self.current_artist_collection:
artist.label_collection.append(self, merge_on_conflict=merge, merge_into_existing=False)
artist._build_recursive_structures(build_version=build_version, merge=merge)
@property
def indexing_values(self) -> List[Tuple[str, object]]:
return [
@ -789,7 +635,7 @@ class Label(Base):
]
@property
def options(self) -> List[DatabaseObject]:
def options(self) -> List[P]:
options = [self]
options.extend(self.current_artist_collection.shallow_list)
options.extend(self.album_collection.shallow_list)

View File

@ -7,11 +7,11 @@ from ..utils.enums.source import SourcePages, SourceTypes
from ..utils.config import youtube_settings
from .metadata import Mapping, Metadata
from .parents import DatabaseObject
from .parents import OuterProxy
from .collection import Collection
class Source(DatabaseObject):
class Source(OuterProxy):
"""
create somehow like that
```python
@ -19,6 +19,13 @@ class Source(DatabaseObject):
Source(src="youtube", url="https://youtu.be/dfnsdajlhkjhsd")
```
"""
page_enum: SourcePages
referer_page: SourcePages
url: str
audio_url: str
COLLECTION_STRING_ATTRIBUTES = tuple()
SIMPLE_STRING_ATTRIBUTES = {
"page_enum": None,
@ -27,21 +34,11 @@ class Source(DatabaseObject):
"audio_url": None
}
def __init__(
self,
page_enum: SourcePages,
url: str = None,
id_: str = None,
referer_page: SourcePages = None,
adio_url: str = None
) -> None:
DatabaseObject.__init__(self, id_=id_)
def __init__(self, page_enum: SourcePages, referer_page: SourcePages = None, **kwargs) -> None:
if referer_page is None:
referer_page = page_enum
self.page_enum = page_enum
self.referer_page = page_enum if referer_page is None else referer_page
self.url = url
self.audio_url = adio_url
super().__init__(page_enum=page_enum, referer_page=referer_page, **kwargs)
@classmethod
def match_url(cls, url: str, referer_page: SourcePages) -> Optional["Source"]:

View File

@ -5,7 +5,7 @@ import logging
import requests
from tqdm import tqdm
from .parents import DatabaseObject
from .parents import OuterProxy
from ..utils.config import main_settings, logging_settings
from ..utils.string_processing import fit_to_file_system
@ -13,7 +13,7 @@ from ..utils.string_processing import fit_to_file_system
LOGGER = logging.getLogger("target")
class Target(DatabaseObject):
class Target(OuterProxy):
"""
create somehow like that
```python

View File

@ -1,6 +1,6 @@
from typing import Optional, List
from ...objects import DatabaseObject, Artist, Album, Song
from ...objects import Artist, Album, Song, DatabaseObject
class Query:
def __init__(