Skip to content

Commit

Permalink
[ 1.0.75 ] * Added service get_cover_image_file to get the contents…
Browse files Browse the repository at this point in the history
… of an image url and transfer the contents to the local file system. This service should only be used to download images for playlists that contain public domain images. It should not be used to download copyright protected images, as that would violate the Spotify Web API Terms of Service.

  * Updated underlying `spotifywebapiPython` package requirement to version 1.0.129.
  • Loading branch information
thlucas1 committed Dec 21, 2024
1 parent cd3973b commit 5b5db36
Show file tree
Hide file tree
Showing 9 changed files with 149 additions and 4 deletions.
5 changes: 5 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,11 @@ Change are listed in reverse chronological order (newest to oldest).

<span class="changelog">

###### [ 1.0.75 ] - 2024/12/21

* Added service `get_cover_image_file` to get the contents of an image url and transfer the contents to the local file system. This service should only be used to download images for playlists that contain public domain images. It should not be used to download copyright protected images, as that would violate the Spotify Web API Terms of Service.
* Updated underlying `spotifywebapiPython` package requirement to version 1.0.129.

###### [ 1.0.74 ] - 2024/12/20

* Updated underlying `spotifywebapiPython` package requirement to version 1.0.128.
Expand Down
2 changes: 1 addition & 1 deletion LICENSE
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
MIT License

Copyright (c) 2019 - 2023 Joakim Sørensen @ludeeus
Copyright (c) 2019 - 2025 Todd Lucas @thlucas1

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
Expand Down
26 changes: 26 additions & 0 deletions custom_components/spotifyplus/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -114,6 +114,7 @@
SERVICE_SPOTIFY_GET_BROWSE_CATEGORYS_LIST:str = 'get_browse_categorys_list'
SERVICE_SPOTIFY_GET_CATEGORY_PLAYLISTS:str = 'get_category_playlists'
SERVICE_SPOTIFY_GET_CHAPTER:str = 'get_chapter'
SERVICE_SPOTIFY_GET_COVER_IMAGE_FILE:str = 'get_cover_image_file'
SERVICE_SPOTIFY_GET_EPISODE:str = 'get_episode'
SERVICE_SPOTIFY_GET_EPISODE_FAVORITES:str = 'get_episode_favorites'
SERVICE_SPOTIFY_GET_FEATURED_PLAYLISTS:str = 'get_featured_playlists'
Expand Down Expand Up @@ -428,6 +429,14 @@
}
)

SERVICE_SPOTIFY_GET_COVER_IMAGE_FILE_SCHEMA = vol.Schema(
{
vol.Required("entity_id"): cv.entity_id,
vol.Required("image_url"): cv.string,
vol.Required("output_path"): cv.string,
}
)

SERVICE_SPOTIFY_GET_EPISODE_SCHEMA = vol.Schema(
{
vol.Required("entity_id"): cv.entity_id,
Expand Down Expand Up @@ -1253,6 +1262,14 @@ async def service_handle_spotify_command(service: ServiceCall) -> None:
_logsi.LogVerbose(STAppMessages.MSG_SERVICE_EXECUTE % (service.service, entity.name))
await hass.async_add_executor_job(entity.service_spotify_follow_users, ids)

elif service.service == SERVICE_SPOTIFY_GET_COVER_IMAGE_FILE:

# get cover image file.
image_url = service.data.get("image_url")
output_path = service.data.get("output_path")
_logsi.LogVerbose(STAppMessages.MSG_SERVICE_EXECUTE % (service.service, entity.name))
await hass.async_add_executor_job(entity.service_spotify_get_cover_image_file, image_url, output_path)

elif service.service == SERVICE_SPOTIFY_PLAYER_MEDIA_PAUSE:

# pause media play.
Expand Down Expand Up @@ -2554,6 +2571,15 @@ def _GetEntityFromServiceData(hass:HomeAssistant, service:ServiceCall, field_id:
supports_response=SupportsResponse.ONLY,
)

_logsi.LogObject(SILevel.Verbose, STAppMessages.MSG_SERVICE_REQUEST_REGISTER % SERVICE_SPOTIFY_GET_COVER_IMAGE_FILE, SERVICE_SPOTIFY_GET_COVER_IMAGE_FILE_SCHEMA)
hass.services.async_register(
DOMAIN,
SERVICE_SPOTIFY_GET_COVER_IMAGE_FILE,
service_handle_spotify_command,
schema=SERVICE_SPOTIFY_GET_COVER_IMAGE_FILE_SCHEMA,
supports_response=SupportsResponse.NONE,
)

_logsi.LogObject(SILevel.Verbose, STAppMessages.MSG_SERVICE_REQUEST_REGISTER % SERVICE_SPOTIFY_GET_EPISODE, SERVICE_SPOTIFY_GET_EPISODE_SCHEMA)
hass.services.async_register(
DOMAIN,
Expand Down
4 changes: 2 additions & 2 deletions custom_components/spotifyplus/manifest.json
Original file line number Diff line number Diff line change
Expand Up @@ -18,10 +18,10 @@
"requests_oauthlib>=1.3.1",
"soco>=0.30.4",
"smartinspectPython>=3.0.33",
"spotifywebapiPython>=1.0.128",
"spotifywebapiPython>=1.0.129",
"urllib3>=1.21.1,<1.27",
"zeroconf>=0.132.2"
],
"version": "1.0.74",
"version": "1.0.75",
"zeroconf": [ "_spotify-connect._tcp.local." ]
}
50 changes: 50 additions & 0 deletions custom_components/spotifyplus/media_player.py
Original file line number Diff line number Diff line change
Expand Up @@ -3674,6 +3674,56 @@ def service_spotify_get_chapter(
_logsi.LeaveMethod(SILevel.Debug, apiMethodName)


def service_spotify_get_cover_image_file(
self,
imageUrl:str,
outputPath:str,
) -> None:
"""
Gets the contents of an image url and transfers the contents to the local file system.
Args:
imageUrl (str | list[ImageObject]):
The cover image url whose contents are to be retrieved.
outputPath (str):
Fully-qualified path to store the downloaded image to.
The output path supports the replacement of the following keyword parameters:
- `{dotfileextn}` - a "." followed by the file extension based on response content
type (for known types: JPG,PNG,APNG,BMP,GIF - defaults to JPG).
This method should only be used to download images for playlists that contain
public domain images. It should not be used to download copyright protected images,
as that would violate the Spotify Web API Terms of Service.
"""
apiMethodName:str = 'service_spotify_get_cover_image_file'
apiMethodParms:SIMethodParmListContext = None

try:

# trace.
apiMethodParms = _logsi.EnterMethodParmList(SILevel.Debug, apiMethodName)
apiMethodParms.AppendKeyValue("imageUrl", imageUrl)
apiMethodParms.AppendKeyValue("outputPath", outputPath)
_logsi.LogMethodParmList(SILevel.Verbose, "Spotify Get Cover Image File Service", apiMethodParms)

# get cover image file.
_logsi.LogVerbose("Retrieving cover image file")
self.data.spotifyClient.GetCoverImageFile(imageUrl, outputPath)

# the following exceptions have already been logged, so we just need to
# pass them back to HA for display in the log (or service UI).
except SpotifyApiError as ex:
raise ServiceValidationError(ex.Message)
except SpotifyWebApiError as ex:
raise ServiceValidationError(ex.Message)

finally:

# trace.
_logsi.LeaveMethod(SILevel.Debug, apiMethodName)


def service_spotify_get_episode(
self,
episodeId:str=None,
Expand Down
28 changes: 28 additions & 0 deletions custom_components/spotifyplus/services.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -963,6 +963,34 @@ get_chapter:
selector:
text:

get_cover_image_file:
name: Get Cover Image File
description: Gets the contents of an image url and transfers the contents to the local file system.
fields:
entity_id:
name: Entity ID
description: Entity ID of the SpotifyPlus device that will make the request to the Spotify Web API.
example: "media_player.spotifyplus_username"
required: true
selector:
entity:
integration: spotifyplus
domain: media_player
image_url:
name: Image URL
description: The cover image url whose contents are to be retrieved.
example: "https://i.scdn.co/image/ab67616d0000b27316c019c87a927829804caf0b"
required: true
selector:
text:
output_path:
name: Output Path
description: Fully-qualified path to store the downloaded image to.
example: "/config/www/images/cover_file_image.jpg"
required: true
selector:
text:

get_episode:
name: Get Episode
description: Get Spotify catalog information for a single episode identified by its unique Spotify ID.
Expand Down
18 changes: 18 additions & 0 deletions custom_components/spotifyplus/strings.json
Original file line number Diff line number Diff line change
Expand Up @@ -640,6 +640,24 @@
}
}
},
"get_cover_image_file": {
"name": "Get Cover Image File",
"description": "Gets the contents of an image url and transfers the contents to the local file system.",
"fields": {
"entity_id": {
"name": "Entity ID",
"description": "Entity ID of the SpotifyPlus device that will make the request to the Spotify Web API."
},
"image_url": {
"name": "Image URL",
"description": "The cover image url whose contents are to be retrieved."
},
"output_path": {
"name": "Output Path",
"description": "Fully-qualified path to store the downloaded image to."
}
}
},
"get_episode": {
"name": "Get Episode",
"description": "Get Spotify catalog information for a single episode.",
Expand Down
18 changes: 18 additions & 0 deletions custom_components/spotifyplus/translations/en.json
Original file line number Diff line number Diff line change
Expand Up @@ -640,6 +640,24 @@
}
}
},
"get_cover_image_file": {
"name": "Get Cover Image File",
"description": "Gets the contents of an image url and transfers the contents to the local file system.",
"fields": {
"entity_id": {
"name": "Entity ID",
"description": "Entity ID of the SpotifyPlus device that will make the request to the Spotify Web API."
},
"image_url": {
"name": "Image URL",
"description": "The cover image url whose contents are to be retrieved."
},
"output_path": {
"name": "Output Path",
"description": "Fully-qualified path to store the downloaded image to."
}
}
},
"get_episode": {
"name": "Get Episode",
"description": "Get Spotify catalog information for a single episode.",
Expand Down
2 changes: 1 addition & 1 deletion requirements.txt
Original file line number Diff line number Diff line change
Expand Up @@ -4,4 +4,4 @@ homeassistant==2024.5.0
ruff==0.1.3
soco>=0.30.4
smartinspectPython>=3.0.33
spotifywebapiPython>=1.0.128
spotifywebapiPython>=1.0.129

0 comments on commit 5b5db36

Please sign in to comment.