spot2txt

Export Spotify Playlist Listings as Plaintext
git clone git://git.alexkarle.com.com/spot2txt
Log | Files | Refs | README

commit 3052f31ffdaac2c8ec288fca73af1a7418d05daa (patch)
parent e3e64330f1fa44f51ef3f87cb4a99c4a75410432
Author: Alex Karle <alex@alexkarle.com>
Date:   Tue,  4 Feb 2025 20:38:26 -0500

Add CLI that pages through playlists using token

Diffstat:
Acli.pl | 54++++++++++++++++++++++++++++++++++++++++++++++++++++++
Aget-token.pl | 74++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Dspotilist.pl | 74--------------------------------------------------------------------------
3 files changed, 128 insertions(+), 74 deletions(-)

diff --git a/cli.pl b/cli.pl @@ -0,0 +1,54 @@ +#!/usr/bin/env perl +use strict; +use warnings; + +# utf8 shenanis -- files written and stdout both utf8 +use utf8; +use open qw(:std :encoding(UTF-8)); + +use LWP::UserAgent; +use JSON::PP; + +if (!$ENV{SPOTIFY_TOKEN}) { + die "SPOTIFY_TOKEN not set in environment\n"; +} + +if (!@ARGV) { + die "usage: $0 username\n"; +} + +my $user = $ARGV[0]; +my $API = "https://api.spotify.com/v1"; + +sub get_playlists { + my $ua = LWP::UserAgent->new(); + my @playlists; + my $url = "$API/users/$user/playlists"; + while (1) { + $ua->default_header( + "Authorization" => "Bearer $ENV{SPOTIFY_TOKEN}" + ); + my $res = $ua->get($url); + if (!$res->is_success) { + use Data::Dumper; + print(Dumper($res)); + my $err = $res->decoded_content; + die "Failed to fetch playlists: $err"; + } + my $j = decode_json($res->decoded_content); + foreach my $item (@{$j->{items}}) { + push(@playlists, $item); + } + if (!$j->{next}) { + last; + } + print("Paging: $url\n"); + $url = $j->{next}; + } + return @playlists; +} + +my @p = get_playlists(); +print($_->{name} . "\n") for @p; + +exit 0; diff --git a/get-token.pl b/get-token.pl @@ -0,0 +1,74 @@ +#!/usr/bin/env perl +use strict; +use warnings; + +use Mojolicious::Lite; +use LWP::UserAgent; +use MIME::Base64; +use JSON::PP; + +my $CLIENT_ID = $ENV{SPOTIFY_CLIENT_ID}; +my $CLIENT_SECRET = $ENV{SPOTIFY_CLIENT_SECRET}; +if (!$CLIENT_ID || !$CLIENT_SECRET) { + die "Spotify Env Vars not set\n"; +} + +my $AUTH_URL = "https://accounts.spotify.com/authorize" + . "?client_id=$CLIENT_ID" + . "&response_type=code" + . "&redirect_uri=http://localhost:3000/auth" + . "&scope=playlist-read-private%20playlist-read-collaborative" + . "&state=" . int(rand() * 100); + +get '/' => sub { + my $c = shift; + $c->render( + template => "index", + AUTH_URL => $AUTH_URL, + ); +}; + +get 'auth' => sub { + my $c = shift; + + # TODO: check state too if ever productionize / allow multiple + # users instead of local-only + my $code = $c->param("code"); + if (!$code) { + $c->render(text => "Failed to Authorize; Go back and try again"); + return; + } + my $ua = LWP::UserAgent->new(); + my $hash = encode_base64("$CLIENT_ID:$CLIENT_SECRET", ""); + $ua->default_header('Authorization' => "Basic $hash"); + my %form = ( + grant_type => "authorization_code", + code => $code, + redirect_uri => "http://localhost:3000/auth", + ); + my $res = $ua->post( + "https://accounts.spotify.com/api/token", + \%form, + ); + if (!$res->is_success) { + my $err = $res->decoded_content; + return $c->render(text => "Error Authenticating: $err"); + } + my $json = decode_json($res->decoded_content); + my $tok = $json->{access_token} . ""; + $c->render(text => $tok); +}; + + +app->start; + +__DATA__ + +@@index.html.ep +<h1>Spotify Playlist Exporter</h1> +<p>Hello and welcome to the Spotify Playlist Exporter!</p> +<p>To start, first log in to Spotify and authorize this +app by clicking the link below:</p> +<a href=<%= $AUTH_URL %>> +Authorize +</a> diff --git a/spotilist.pl b/spotilist.pl @@ -1,74 +0,0 @@ -#!/usr/bin/env perl -use strict; -use warnings; - -use Mojolicious::Lite; -use LWP::UserAgent; -use MIME::Base64; -use JSON::PP; - -my $CLIENT_ID = $ENV{SPOTIFY_CLIENT_ID}; -my $CLIENT_SECRET = $ENV{SPOTIFY_CLIENT_SECRET}; -if (!$CLIENT_ID || !$CLIENT_SECRET) { - die "Spotify Env Vars not set\n"; -} - -my $AUTH_URL = "https://accounts.spotify.com/authorize" - . "?client_id=$CLIENT_ID" - . "&response_type=code" - . "&redirect_uri=http://localhost:3000/auth" - . "&scope=playlist-read-private%20playlist-read-collaborative" - . "&state=" . int(rand() * 100); - -get '/' => sub { - my $c = shift; - $c->render( - template => "index", - AUTH_URL => $AUTH_URL, - ); -}; - -get 'auth' => sub { - my $c = shift; - - # TODO: check state too if ever productionize / allow multiple - # users instead of local-only - my $code = $c->param("code"); - if (!$code) { - $c->render(text => "Failed to Authorize; Go back and try again"); - return; - } - my $ua = LWP::UserAgent->new(); - my $hash = encode_base64("$CLIENT_ID:$CLIENT_SECRET", ""); - $ua->default_header('Authorization' => "Basic $hash"); - my %form = ( - grant_type => "authorization_code", - code => $code, - redirect_uri => "http://localhost:3000/auth", - ); - my $res = $ua->post( - "https://accounts.spotify.com/api/token", - \%form, - ); - if (!$res->is_success) { - my $err = $res->decoded_content; - return $c->render(text => "Error Authenticating: $err"); - } - my $json = decode_json($res->decoded_content); - my $tok = $json->{access_token} . ""; - return $c->render(text => $tok); -}; - - -app->start; - -__DATA__ - -@@index.html.ep -<h1>Spotify Playlist Exporter</h1> -<p>Hello and welcome to the Spotify Playlist Exporter!</p> -<p>To start, first log in to Spotify and authorize this -app by clicking the link below:</p> -<a href=<%= $AUTH_URL %>> -Authorize -</a>