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

handle spotify web URLs as well #379

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 9 additions & 0 deletions custom_components/spotcast/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,7 @@
get_random_playlist_from_category,
get_search_results,
is_valid_uri,
url_to_spotify_uri,
)

from .spotcast_controller import SpotcastController
Expand Down Expand Up @@ -229,6 +230,14 @@ def start_casting(call: ha_core.ServiceCall):
# remove ? from badly formatted URI
uri = uri.split("?")[0]

if uri.startswith("http"):
try:
u = url_to_spotify_uri(uri)
_LOGGER.debug("converted web URL %s to spotify URI %s", uri, u)
uri = u
except ValueError:
_LOGGER.error("invalid web URL provided, could not convert to spotify URI: %s", uri)

if not is_valid_uri(uri):
_LOGGER.error("Invalid URI provided, aborting casting")
return
Expand Down
22 changes: 21 additions & 1 deletion custom_components/spotcast/helpers.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
import asyncio
import logging
import requests
import urllib
import urllib.parse
import difflib
import random
from functools import partial, wraps
Expand Down Expand Up @@ -171,6 +171,26 @@ def get_random_playlist_from_category(spotify_client:spotipy.Spotify, category:s

return chosen['uri']


def url_to_spotify_uri(url: str) -> str:
Copy link
Collaborator

@fcusson fcusson Apr 14, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

do not return None on error, Raise an error instead to let the parent process decide what to do on error

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sure, makes sense. What's the convention around error types for the project?

"""
Convert a spotify web url (e.g. https://open.spotify.com/track/XXXX) to
a spotify-style URI (spotify:track:XXXX). Returns None on error.
"""

o: urllib.parse.ParseResult
# will raise ValueError if URL is invalid
o = urllib.parse.urlparse(url)

if o.hostname != "open.spotify.com":
raise ValueError('Spotify URLs must have a hostname of "open.spotify.com"')

path = o.path.split("/")
if len(path) != 3:
raise ValueError('Spotify URLs must be of the form "https://open.spotify.com/<kind>/<target>"')

return f'spotify:{path[1]}:{path[2]}'

def is_valid_uri(uri: str) -> bool:

# list of possible types
Expand Down