Skip to content

Instantly share code, notes, and snippets.

@yordis
Forked from Boettner-eric/playlist.ex
Created October 3, 2023 16:17
Show Gist options
  • Select an option

  • Save yordis/16de795562bfc8baf57c681a4b98eb93 to your computer and use it in GitHub Desktop.

Select an option

Save yordis/16de795562bfc8baf57c681a4b98eb93 to your computer and use it in GitHub Desktop.

Revisions

  1. @Boettner-eric Boettner-eric revised this gist Sep 21, 2023. 1 changed file with 4 additions and 9 deletions.
    13 changes: 4 additions & 9 deletions playlist.ex
    Original file line number Diff line number Diff line change
    @@ -52,15 +52,10 @@ defmodule Spotify do

    defp parse_playlist_resp(%HTTPoison.Response{status_code: 200, body: body}) do
    Poison.decode!(body)
    |> normalize_format()
    end

    defp normalize_format(%{"tracks" => %{"next" => next, "items" => items}}) do
    {next, items}
    end

    defp normalize_format(%{"next" => next, "items" => items}) do
    {next, items}
    |> case do
    %{"tracks" => %{"next" => next, "items" => items}} -> {next, items}
    %{"next" => next, "items" => items} -> {next, items}
    end
    end

    defp format_track(track) do
  2. @Boettner-eric Boettner-eric revised this gist Sep 8, 2023. 1 changed file with 35 additions and 37 deletions.
    72 changes: 35 additions & 37 deletions playlist.ex
    Original file line number Diff line number Diff line change
    @@ -15,35 +15,51 @@ defmodule Spotify do
    "grant_type=client_credentials&client_id=#{client_id}&client_secret=#{client_secret}",
    [{"Content-Type", "application/x-www-form-urlencoded"}]
    )
    |> parse_resp()
    |> parse_token_resp()
    end

    def get_playlists({:ok, access_token, token_type}, url \\ @playlist_url) do
    next =
    HTTPoison.get!(url, generate_headers(access_token))
    |> parse_playlist_tracks()
    defp parse_token_resp(%HTTPoison.Response{status_code: 200, body: body}) do
    %{
    "access_token" => access_token,
    "token_type" => token_type,
    "expires_in" => _expires_in
    } = Poison.decode!(body)

    unless is_nil(next) do
    get_playlists({:ok, access_token, token_type}, next)
    end
    {:ok, access_token, token_type}
    end

    defp parse_playlist_tracks(%HTTPoison.Response{status_code: 200, body: body}) do
    {next, items} =
    Poison.decode!(body)
    |> decode_resp()
    defp parse_token_resp(%HTTPoison.Response{status_code: status_code, body: body}) do
    {:error, status_code, Poison.decode!(body)}
    end

    Enum.map(items, &format_track/1)
    |> write_file()
    defp parse_token_resp(_) do
    {:error, :unexpected_response}
    end

    next
    def get_playlist({:ok, access_token, token_type}, list \\ [], url \\ @playlist_url) do
    {next, items} =
    HTTPoison.get!(url, generate_headers(access_token))
    |> parse_playlist_resp()

    if is_nil(next) do
    Enum.uniq(list ++ items)
    |> Enum.map(&format_track/1)
    |> write_file()
    else
    get_playlist({:ok, access_token, token_type}, list ++ items, next)
    end
    end

    defp decode_resp(%{"tracks" => %{"next" => next, "items" => items}}) do
    defp parse_playlist_resp(%HTTPoison.Response{status_code: 200, body: body}) do
    Poison.decode!(body)
    |> normalize_format()
    end

    defp normalize_format(%{"tracks" => %{"next" => next, "items" => items}}) do
    {next, items}
    end

    defp decode_resp(%{"next" => next, "items" => items}) do
    defp normalize_format(%{"next" => next, "items" => items}) do
    {next, items}
    end

    @@ -59,30 +75,12 @@ defmodule Spotify do
    ]
    end

    defp parse_resp(%HTTPoison.Response{status_code: 200, body: body}) do
    %{
    "access_token" => access_token,
    "token_type" => token_type,
    "expires_in" => _expires_in
    } = Poison.decode!(body)

    {:ok, access_token, token_type}
    end

    defp parse_resp(%HTTPoison.Response{status_code: status_code, body: body}) do
    {:error, status_code, Poison.decode!(body)}
    end

    defp parse_resp(_) do
    {:error, :unexpected_response}
    end

    def write_file(tracks) do
    defp write_file(tracks) do
    {:ok, file} = File.open("playlist.txt", [:append, {:delayed_write, 100, 20}])
    Enum.map(tracks, &IO.binwrite(file, "#{&1}\n"))
    File.close(file)
    end
    end

    Spotify.get_token()
    |> Spotify.get_playlists()
    |> Spotify.get_playlist()
  3. @Boettner-eric Boettner-eric created this gist Sep 8, 2023.
    88 changes: 88 additions & 0 deletions playlist.ex
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,88 @@
    Mix.install([:httpoison, :poison])

    defmodule Spotify do
    [playlist_id] = System.argv()

    @token_url "https://accounts.spotify.com/api/token"
    @playlist_url "https://api.spotify.com/v1/playlists/#{playlist_id}"

    def get_token() do
    client_id = System.get_env("SPOTIFY_CLIENT_ID")
    client_secret = System.get_env("SPOTIFY_CLIENT_SECRET")

    HTTPoison.post!(
    @token_url,
    "grant_type=client_credentials&client_id=#{client_id}&client_secret=#{client_secret}",
    [{"Content-Type", "application/x-www-form-urlencoded"}]
    )
    |> parse_resp()
    end

    def get_playlists({:ok, access_token, token_type}, url \\ @playlist_url) do
    next =
    HTTPoison.get!(url, generate_headers(access_token))
    |> parse_playlist_tracks()

    unless is_nil(next) do
    get_playlists({:ok, access_token, token_type}, next)
    end
    end

    defp parse_playlist_tracks(%HTTPoison.Response{status_code: 200, body: body}) do
    {next, items} =
    Poison.decode!(body)
    |> decode_resp()

    Enum.map(items, &format_track/1)
    |> write_file()

    next
    end

    defp decode_resp(%{"tracks" => %{"next" => next, "items" => items}}) do
    {next, items}
    end

    defp decode_resp(%{"next" => next, "items" => items}) do
    {next, items}
    end

    defp format_track(track) do
    track["track"]["name"] <>
    " - " <> (Enum.map(track["track"]["artists"], & &1["name"]) |> Enum.join(", "))
    end

    defp generate_headers(access_token) do
    [
    {"Authorization", "Bearer #{access_token}"},
    {"Content-Type", "application/json"}
    ]
    end

    defp parse_resp(%HTTPoison.Response{status_code: 200, body: body}) do
    %{
    "access_token" => access_token,
    "token_type" => token_type,
    "expires_in" => _expires_in
    } = Poison.decode!(body)

    {:ok, access_token, token_type}
    end

    defp parse_resp(%HTTPoison.Response{status_code: status_code, body: body}) do
    {:error, status_code, Poison.decode!(body)}
    end

    defp parse_resp(_) do
    {:error, :unexpected_response}
    end

    def write_file(tracks) do
    {:ok, file} = File.open("playlist.txt", [:append, {:delayed_write, 100, 20}])
    Enum.map(tracks, &IO.binwrite(file, "#{&1}\n"))
    File.close(file)
    end
    end

    Spotify.get_token()
    |> Spotify.get_playlists()