Compare commits

..

2 Commits

Author SHA1 Message Date
274f1bce90 feat: implemented fetching of artworks on compile
All checks were successful
ci/woodpecker/push/woodpecker Pipeline was successful
ci/woodpecker/pr/woodpecker Pipeline was successful
2024-06-11 14:54:36 +02:00
b1a306f3f3 fix: implemented artwork.add_data 2024-06-11 14:34:58 +02:00
7 changed files with 72 additions and 35 deletions

View File

@ -1,15 +1,13 @@
import logging
import music_kraken import music_kraken
import logging
print("Setting logging-level to DEBUG") print("Setting logging-level to DEBUG")
logging.getLogger().setLevel(logging.DEBUG) logging.getLogger().setLevel(logging.DEBUG)
if __name__ == "__main__": if __name__ == "__main__":
commands = [ commands = [
"s: #a Crystal F", "s: #a Ghost Bath",
"10",
"1",
"3",
] ]

View File

@ -107,7 +107,7 @@ def write_metadata_to_target(metadata: Metadata, target: Target, song: Song):
mime="image/jpeg", mime="image/jpeg",
type=3, type=3,
desc=u"Cover", desc=u"Cover",
data=converted_target.read_bytes(), data=converted_target.raw_content,
) )
) )
id3_object.frames.delall("USLT") id3_object.frames.delall("USLT")

View File

@ -1,12 +1,12 @@
from __future__ import annotations from __future__ import annotations
import copy
import inspect
import logging import logging
import threading import threading
import time import time
from typing import List, Dict, Optional, Set from typing import TYPE_CHECKING, Dict, List, Optional, Set
from urllib.parse import urlparse, urlunsplit, ParseResult from urllib.parse import ParseResult, urlparse, urlunsplit
import copy
import inspect
import requests import requests
import responses import responses
@ -14,12 +14,15 @@ from tqdm import tqdm
from .cache import Cache from .cache import Cache
from .rotating import RotatingProxy from .rotating import RotatingProxy
from ..objects import Target
if TYPE_CHECKING:
from ..objects import Target
from ..utils import request_trace from ..utils import request_trace
from ..utils.string_processing import shorten_display_url
from ..utils.config import main_settings from ..utils.config import main_settings
from ..utils.support_classes.download_result import DownloadResult
from ..utils.hacking import merge_args from ..utils.hacking import merge_args
from ..utils.string_processing import shorten_display_url
from ..utils.support_classes.download_result import DownloadResult
class Connection: class Connection:

View File

@ -2,8 +2,10 @@ from __future__ import annotations
from copy import copy from copy import copy
from dataclasses import dataclass, field from dataclasses import dataclass, field
from functools import cached_property
from typing import Dict, List, Optional, Set, Tuple, Type, TypedDict, Union from typing import Dict, List, Optional, Set, Tuple, Type, TypedDict, Union
from ..connection import Connection
from ..utils import create_dataclass_instance, custom_hash from ..utils import create_dataclass_instance, custom_hash
from ..utils.config import main_settings from ..utils.config import main_settings
from ..utils.enums import PictureType from ..utils.enums import PictureType
@ -13,6 +15,9 @@ from .metadata import ID3Timestamp
from .metadata import Mapping as id3Mapping from .metadata import Mapping as id3Mapping
from .metadata import Metadata from .metadata import Metadata
from .parents import OuterProxy as Base from .parents import OuterProxy as Base
from .target import Target
artwork_connection: Connection = Connection(module="artwork")
@dataclass @dataclass
@ -20,7 +25,7 @@ class ArtworkVariant:
url: str url: str
width: Optional[int] = None width: Optional[int] = None
height: Optional[int] = None height: Optional[int] = None
image_format: Optional[str] = "" image_format: Optional[str] = None
def __hash__(self) -> int: def __hash__(self) -> int:
return custom_hash(self.url) return custom_hash(self.url)
@ -31,6 +36,26 @@ class ArtworkVariant:
def __contains__(self, other: str) -> bool: def __contains__(self, other: str) -> bool:
return custom_hash(other) == hash(self.url) return custom_hash(other) == hash(self.url)
def __merge__(self, other: ArtworkVariant) -> None:
for key, value in other.__dict__.items():
if value is None:
continue
if getattr(self, key) is None:
setattr(self, key, value)
@cached_property
def target(self) -> Target:
return Target.temp()
def fetch(self) -> None:
global artwork_connection
r = artwork_connection.get(self.url, name=hash_url(url))
if r is None:
return
self.target.raw_content = r.content
@dataclass @dataclass
class Artwork: class Artwork:
@ -55,10 +80,9 @@ class Artwork:
variant = self.search_variant(kwargs.get("url")) variant = self.search_variant(kwargs.get("url"))
if variant is None: if variant is None:
variant, kwargs = create_dataclass_instance(ArtworkVariant, **kwargs) variant, kwargs = create_dataclass_instance(ArtworkVariant, kwargs)
self.variants.append(variant) self.variants.append(variant)
variant.url = url
variant.__dict__.update(kwargs) variant.__dict__.update(kwargs)
@property @property
@ -67,6 +91,10 @@ class Artwork:
return None return None
return self.variants[0].url return self.variants[0].url
def fetch(self) -> None:
for variant in self.variants:
variant.fetch()
class ArtworkCollection: class ArtworkCollection:
""" """
@ -91,8 +119,6 @@ class ArtworkCollection:
self._data = [] self._data = []
self.extend(data) self.extend(data)
def search_artwork(self, url: str) -> Optional[ArtworkVariant]: def search_artwork(self, url: str) -> Optional[ArtworkVariant]:
for artwork in self._data: for artwork in self._data:
if url in artwork: if url in artwork:
@ -106,18 +132,19 @@ class ArtworkCollection:
def _create_new_artwork(self, **kwargs) -> Tuple[Artwork, dict]: def _create_new_artwork(self, **kwargs) -> Tuple[Artwork, dict]:
kwargs["artwork_type"] = kwargs.get("artwork_type", self.artwork_type) kwargs["artwork_type"] = kwargs.get("artwork_type", self.artwork_type)
return create_dataclass_instance(ArtworkVariant, dict(**kwargs)) return create_dataclass_instance(Artwork, dict(**kwargs))
def add_data(self, url: str, **kwargs) -> None: def add_data(self, url: str, **kwargs) -> Artwork:
kwargs["url"] = url kwargs["url"] = url
artwork = self.search_artwork(url) artwork = self.search_artwork(url)
if artwork is None: if artwork is None:
artwork, kwargs = self._create_new_artwork(url=url) artwork, kwargs = self._create_new_artwork(**kwargs)
self._data.append(artwork) self._data.append(artwork)
artwork.add_data(url, **kwargs) artwork.add_data(**kwargs)
return artwork
def append(self, value: Union[Artwork, ArtworkVariant, dict], **kwargs): def append(self, value: Union[Artwork, ArtworkVariant, dict], **kwargs):
""" """
@ -145,9 +172,7 @@ class ArtworkCollection:
This will make the artworks ready for download This will make the artworks ready for download
""" """
for artwork in self._data: for artwork in self._data:
for variants in artwork.variants: artwork.fetch()
pass
pass
def __merge__(self, other: ArtworkCollection, **kwargs) -> None: def __merge__(self, other: ArtworkCollection, **kwargs) -> None:
self.parent_artworks.update(other.parent_artworks) self.parent_artworks.update(other.parent_artworks)

View File

@ -1,17 +1,17 @@
from __future__ import annotations from __future__ import annotations
from pathlib import Path
from typing import List, Tuple, TextIO, Union, Optional
import logging import logging
import random import random
from pathlib import Path
from typing import List, Optional, TextIO, Tuple, Union
import requests import requests
from tqdm import tqdm from tqdm import tqdm
from .parents import OuterProxy from ..utils.config import logging_settings, main_settings
from ..utils.shared import HIGHEST_ID from ..utils.shared import HIGHEST_ID
from ..utils.config import main_settings, logging_settings
from ..utils.string_processing import fit_to_file_system from ..utils.string_processing import fit_to_file_system
from .parents import OuterProxy
LOGGER = logging.getLogger("target") LOGGER = logging.getLogger("target")
@ -117,3 +117,11 @@ class Target(OuterProxy):
def read_bytes(self) -> bytes: def read_bytes(self) -> bytes:
return self.file_path.read_bytes() return self.file_path.read_bytes()
@property
def raw_content(self) -> bytes:
return self.file_path.read_bytes()
@raw_content.setter
def raw_content(self, content: bytes):
self.file_path.write_bytes(content)

View File

@ -156,6 +156,7 @@ def create_dataclass_instance(t, data: dict):
Tuple[Type, dict]: The created instance and a dict, containing the data, which was not used in the creation Tuple[Type, dict]: The created instance and a dict, containing the data, which was not used in the creation
""" """
data = {k: v for k, v in data.items() if hasattr(t, k)} needed_data = {k: v for k, v in data.items() if k in t.__dataclass_fields__}
removed_data = {k: v for k, v in data.items() if not hasattr(t, k)} removed_data = {k: v for k, v in data.items() if k not in t.__dataclass_fields__}
return t(**data), removed_data
return t(**needed_data), removed_data

View File

@ -1,3 +1,4 @@
import re
import string import string
from functools import lru_cache from functools import lru_cache
from pathlib import Path from pathlib import Path
@ -238,4 +239,5 @@ def is_url(value: Any) -> bool:
if not isinstance(value, str): if not isinstance(value, str):
return True return True
return re.match(URL_PATTERN, query) is not None # value has to be a string
return re.match(URL_PATTERN, value) is not None