diff --git a/apps/toniefy/assets/static/images/how-to-get-spotify-uri.gif b/apps/toniefy/assets/static/images/how-to-get-spotify-uri.gif index 3568fcf..9b76cff 100644 Binary files a/apps/toniefy/assets/static/images/how-to-get-spotify-uri.gif and b/apps/toniefy/assets/static/images/how-to-get-spotify-uri.gif differ diff --git a/apps/toniefy/lib/toniex/clients/spotify.ex b/apps/toniefy/lib/toniex/clients/spotify.ex index 9f9fe61..a0b3da7 100644 --- a/apps/toniefy/lib/toniex/clients/spotify.ex +++ b/apps/toniefy/lib/toniex/clients/spotify.ex @@ -1,5 +1,6 @@ defmodule Toniex.Clients.Spotify do @spotify_uri_regex ~r/^spotify:(?(playlist|album|track)):(?[\w\d]+)$/ + @spotify_url_regex ~r/\/(?(playlist|album|track))\/(?[\w\d]+)/ def get_token(refresh_token) do res = @@ -35,7 +36,7 @@ defmodule Toniex.Clients.Spotify do end @doc """ - Get the total duration of a Spotify URI. Returns + Get the total duration of a Spotify URI or URL. Returns Returns `{:ok, duration_ms}` or an error tuple `{:error, any()}`. @@ -47,8 +48,8 @@ defmodule Toniex.Clients.Spotify do """ @spec total_duration(Tesla.Client.t(), String.t()) :: {:ok, integer()} | {:error, :uri_not_supported | any()} - def total_duration(client, uri) do - %{type: type, id: id} = parse_uri(uri) + def total_duration(client, uri_or_url) do + %{type: type, id: id} = parse_uri(uri_or_url) case type do "track" -> @@ -58,7 +59,7 @@ defmodule Toniex.Clients.Spotify do end "album" -> - case get_all_tracks(client, uri) do + case get_all_tracks(client, uri_or_url) do {:ok, tracks} -> duration = Enum.reduce(tracks, 0, fn track, duration -> @@ -72,7 +73,7 @@ defmodule Toniex.Clients.Spotify do end "playlist" -> - case get_all_tracks(client, uri) do + case get_all_tracks(client, uri_or_url) do {:ok, tracks} -> duration = Enum.reduce(tracks, 0, fn track, duration -> @@ -111,7 +112,7 @@ defmodule Toniex.Clients.Spotify do {:ok, list()} | {:error, any()} def get_all_tracks( client, - uri, + uri_or_url, tracks \\ [], page_url \\ "" ) @@ -126,11 +127,11 @@ defmodule Toniex.Clients.Spotify do def get_all_tracks( client, - uri, + uri_or_url, tracks, page_url ) do - %{id: id, type: type} = parse_uri(uri) + %{id: id, type: type} = parse_uri(uri_or_url) url = case type do @@ -148,7 +149,7 @@ defmodule Toniex.Clients.Spotify do case result do {:ok, %{"items" => items, "next" => next}} -> - {:ok, page_tracks} = get_all_tracks(client, uri, items, next) + {:ok, page_tracks} = get_all_tracks(client, uri_or_url, items, next) {:ok, page_tracks ++ tracks} {:error, reason} -> @@ -156,6 +157,34 @@ defmodule Toniex.Clients.Spotify do end end + @doc """ + Parse a spotify URI or URL. + """ + def parse_uri(uri_or_url) do + cond do + String.match?(uri_or_url, @spotify_uri_regex) -> + %{"id" => id, "type" => type} = Regex.named_captures(@spotify_uri_regex, uri_or_url) + %{id: id, type: type} + + String.match?(uri_or_url, @spotify_url_regex) -> + %{"id" => id, "type" => type} = Regex.named_captures(@spotify_url_regex, uri_or_url) + %{id: id, type: type} + + true -> + {:error, :invalid_uri_or_url} + end + end + + @doc """ + Converts a Spotify URL to an URI + """ + def to_uri(url) do + case Regex.named_captures(@spotify_url_regex, url) do + %{"id" => id, "type" => type} -> "spotify:#{type}:#{id}" + _ -> {:error, :invalid_url} + end + end + defp base64_credentials() do config = Application.fetch_env!(:ueberauth, Ueberauth.Strategy.Spotify.OAuth) @@ -165,11 +194,6 @@ defmodule Toniex.Clients.Spotify do Base.encode64("#{client_id}:#{client_secret}") end - defp parse_uri(uri) do - %{"id" => id, "type" => type} = Regex.named_captures(@spotify_uri_regex, uri) - %{id: id, type: type} - end - @spec handle_response(Tesla.Env.result()) :: {:ok, any()} | {:error, any()} defp handle_response(response) do case response do diff --git a/apps/toniefy/lib/toniex/recorder.ex b/apps/toniefy/lib/toniex/recorder.ex index 5d5a769..28ca369 100644 --- a/apps/toniefy/lib/toniex/recorder.ex +++ b/apps/toniefy/lib/toniex/recorder.ex @@ -9,16 +9,16 @@ defmodule Toniex.Recorder do require Logger @upload_dir Application.fetch_env!(:toniex, :upload_dir) - @spotify_uri_regex ~r/^spotify:(?(playlist|album|track)):(?[\w\d]+)$/ @spec enqueue(Toniex.Accounts.User.t(), binary) :: {:error, :invalid_uri | :max_duration_exceeded | any} | {:ok, Oban.Job.t()} - def enqueue(user, uri) do + def enqueue(user, uri_or_url) do client = Accounts.get_session(user, :spotify) |> Spotify.client() - with true <- spotify_uri_valid?(uri), + with true <- spotify_uri_valid?(uri_or_url), + uri <- Spotify.to_uri(uri_or_url), :ok <- spotify_validate_duration(client, uri) do %{ id: Ecto.UUID.generate(), @@ -130,8 +130,11 @@ defmodule Toniex.Recorder do Repo.delete(session) end - defp spotify_uri_valid?(uri) do - String.match?(uri, @spotify_uri_regex) + defp spotify_uri_valid?(uri_or_url) do + case Spotify.parse_uri(uri_or_url) do + m when is_map(m) -> true + _ -> false + end end defp spotify_validate_duration(client, uri) do diff --git a/apps/toniefy/lib/toniex_web/live/recorder_live.ex b/apps/toniefy/lib/toniex_web/live/recorder_live.ex index 78909ab..08d4982 100644 --- a/apps/toniefy/lib/toniex_web/live/recorder_live.ex +++ b/apps/toniefy/lib/toniex_web/live/recorder_live.ex @@ -105,13 +105,13 @@ defmodule ToniexWeb.RecorderLive do

Neue Aufnahme starten

-

Bitte gib eine Spotify URI in das Textfeld ein. Dies kann der Link zu einem einzelnen Lied, einer Playlist oder einem Album sein.

+

Bitte gib eine Spotify URL oder URI in das Textfeld ein. Dies kann der Link zu einem einzelnen Lied, einer Playlist oder einem Album sein.

<%= f = form_for :recorder, "#", [phx_submit: :record] %> <%= text_input f, :uri, required: true, class: "input w-full text-xl py-3", placeholder: "spotify:awesome-track" %>

- <%= link "Wo finde ich die Spotify URI?", to: Routes.static_path(@socket, "/images/how-to-get-spotify-uri.gif"), target: "_blank", class: "link" %> + <%= link "Wo finde ich die Spotify URL?", to: Routes.static_path(@socket, "/images/how-to-get-spotify-uri.gif"), target: "_blank", class: "link" %>

<%= submit "Aufnahme starten", phx_disable_with: "Aufnahme starten...", class: "btn btn-primary" %>