Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Deleting_images v4 #1529

Closed
wants to merge 18 commits into from
Closed
4 changes: 3 additions & 1 deletion .github/workflows/release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -5,13 +5,15 @@ on:
types: [published]
env:
PYTHON_VERSION: "3.11"

jobs:
build-and-publish-pypi:
name: Builds and publishes releases to PyPI
runs-on: ubuntu-latest
outputs:
version: ${{ steps.vars.outputs.tag }}
permissions:
id-token: write
steps:
- uses: actions/[email protected]
- name: Get tag
Expand Down
8 changes: 1 addition & 7 deletions music_assistant/client/client.py
Original file line number Diff line number Diff line change
Expand Up @@ -143,7 +143,7 @@ def get_image_url(self, image: MediaItemImage, size: int = 0) -> str:
f"&w=${size}&h=${size}&fit=cover&a=attention"
)
# return imageproxy url for images that need to be resolved
# the original path is double encoded
# the original path is double encoded 2
encoded_url = urllib.parse.quote(urllib.parse.quote(image.path))
return (
f"{self.server_info.base_url}/imageproxy?path={encoded_url}"
Expand All @@ -157,12 +157,6 @@ def get_media_item_image_url(
size: int = 0,
) -> str | None:
"""Get image URL for MediaItem, QueueItem or ItemMapping."""
# handle queueitem with media_item attribute
if media_item := getattr(item, "media_item", None):
if img := self.music.get_media_item_image(media_item, type):
return self.get_image_url(img, size)
if img := self.music.get_media_item_image(item, type):
return self.get_image_url(img, size)
return None

def subscribe(
Expand Down
26 changes: 0 additions & 26 deletions music_assistant/client/music.py
Original file line number Diff line number Diff line change
Expand Up @@ -532,30 +532,4 @@ def get_media_item_image(
type: ImageType = ImageType.THUMB, # noqa: A002
) -> MediaItemImage | None:
"""Get MediaItemImage for MediaItem, ItemMapping."""
if not item:
# guard for unexpected bad things
return None
# handle image in itemmapping
if item.image and item.image.type == type:
return item.image
# always prefer album image for tracks
album: Album | ItemMapping | None
if album := getattr(item, "album", None):
if album_image := self.get_media_item_image(album, type):
return album_image
# handle regular image within mediaitem
metadata: MediaItemMetadata | None
if metadata := getattr(item, "metadata", None):
for img in metadata.images or []:
if img.type == type:
return cast(MediaItemImage, img)
# retry with album/track artist(s)
artists: list[Artist | ItemMapping] | None
if artists := getattr(item, "artists", None):
for artist in artists:
if artist_image := self.get_media_item_image(artist, type):
return artist_image
# allow landscape fallback
if type == ImageType.THUMB:
return self.get_media_item_image(item, ImageType.LANDSCAPE)
return None
74 changes: 0 additions & 74 deletions music_assistant/server/controllers/metadata.py
Original file line number Diff line number Diff line change
Expand Up @@ -297,33 +297,6 @@ async def get_image_url_for_item(
resolve: bool = True,
) -> str | None:
"""Get url to image for given media media_item."""
if not media_item:
return None
if isinstance(media_item, ItemMapping):
media_item = await self.mass.music.get_item_by_uri(media_item.uri)
if media_item and media_item.metadata.images:
for img in media_item.metadata.images:
if img.type != img_type:
continue
if img.remotely_accessible and not resolve:
continue
if img.remotely_accessible and resolve:
return self.get_image_url(img)
return img.path

# retry with track's album
if media_item.media_type == MediaType.TRACK and media_item.album:
return await self.get_image_url_for_item(media_item.album, img_type, resolve)

# try artist instead for albums
if media_item.media_type == MediaType.ALBUM and media_item.artists:
return await self.get_image_url_for_item(media_item.artists[0], img_type, resolve)

# last resort: track artist(s)
if media_item.media_type == MediaType.TRACK and media_item.artists:
for artist in media_item.artists:
return await self.get_image_url_for_item(artist, img_type, resolve)

return None

def get_image_url(
Expand Down Expand Up @@ -361,30 +334,6 @@ async def get_thumbnail(
return thumbnail

async def handle_imageproxy(self, request: web.Request) -> web.Response:
"""Handle request for image proxy."""
path = request.query["path"]
provider = request.query.get("provider", "builtin")
if provider in ("url", "file"):
# temporary for backwards compatibility
provider = "builtin"
size = int(request.query.get("size", "0"))
image_format = request.query.get("fmt", "png")
if not self.mass.get_provider(provider):
return web.Response(status=404)
if "%" in path:
# assume (double) encoded url, decode it
path = urllib.parse.unquote(path)
with suppress(FileNotFoundError):
image_data = await self.get_thumbnail(
path, size=size, provider=provider, image_format=image_format
)
# we set the cache header to 1 year (forever)
# assuming that images do not/rarely change
return web.Response(
body=image_data,
headers={"Cache-Control": "max-age=31536000", "Access-Control-Allow-Origin": "*"},
content_type=f"image/{image_format}",
)
return web.Response(status=404)

async def create_collage_image(
Expand All @@ -394,29 +343,6 @@ async def create_collage_image(
fanart: bool = False,
) -> MediaItemImage | None:
"""Create collage thumb/fanart image for (in-library) playlist."""
if len(images) < 8 and fanart or len(images) < 3:
# require at least some images otherwise this does not make a lot of sense
return None
try:
# create collage thumb from playlist tracks
# if playlist has no default image (e.g. a local playlist)
dimensions = (2500, 1750) if fanart else (1500, 1500)
img_data = await create_collage(self.mass, images, dimensions)
# always overwrite existing path
async with aiofiles.open(img_path, "wb") as _file:
await _file.write(img_data)
return MediaItemImage(
type=ImageType.FANART if fanart else ImageType.THUMB,
path=img_path,
provider="builtin",
remotely_accessible=False,
)
except Exception as err:
self.logger.warning(
"Error while creating playlist image: %s",
str(err),
exc_info=err if self.logger.isEnabledFor(10) else None,
)
return None

async def _update_artist_metadata(self, artist: Artist, force_refresh: bool = False) -> None:
Expand Down
24 changes: 0 additions & 24 deletions music_assistant/server/helpers/images.py
Original file line number Diff line number Diff line change
Expand Up @@ -25,30 +25,6 @@

async def get_image_data(mass: MusicAssistant, path_or_url: str, provider: str) -> bytes:
"""Create thumbnail from image url."""
# TODO: add local cache here !
if prov := mass.get_provider(provider):
prov: MusicProvider | MetadataProvider
if resolved_image := await prov.resolve_image(path_or_url):
if isinstance(resolved_image, bytes):
return resolved_image
if isinstance(resolved_image, str):
path_or_url = resolved_image
# handle HTTP location
if path_or_url.startswith("http"):
try:
async with mass.http_session.get(path_or_url, raise_for_status=True) as resp:
return await resp.read()
except ClientError as err:
raise FileNotFoundError from err
# handle FILE location (of type image)
if path_or_url.endswith(("jpg", "JPG", "png", "PNG", "jpeg")):
if await asyncio.to_thread(os.path.isfile, path_or_url):
async with aiofiles.open(path_or_url, "rb") as _file:
return await _file.read()
# use ffmpeg for embedded images
if img_data := await get_embedded_image(path_or_url):
return img_data
msg = f"Image not found: {path_or_url}"
raise FileNotFoundError(msg)


Expand Down
4 changes: 2 additions & 2 deletions pyproject.toml
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
[project]
name = "music_assistant"
name = "ma-server-mp"
# The version is set by GH action on release
authors = [
{name = "The Music Assistant Authors", email = "[email protected]"},
Expand All @@ -10,7 +10,7 @@ classifiers = [
"Programming Language :: Python :: 3.12",
]
dependencies = ["aiohttp", "orjson", "mashumaro"]
description = "Music Assistant"
description = "ma-server-mp"
license = {text = "Apache-2.0"}
readme = "README.md"
requires-python = ">=3.11"
Expand Down