spot2txt

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

commit 84efc614a8d3243c04cf4bc7fb83d55cefb4e55a (patch)
parent 2a192891cc9d41ac6baa41489d9fe9f0983c504b
Author: Alex Karle <alex@alexkarle.com>
Date:   Tue,  4 Feb 2025 21:44:59 -0500

Add actual implementation of saving to txt

Diffstat:
M.gitignore | 1+
Mcli.pl | 70+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++---------
2 files changed, 62 insertions(+), 9 deletions(-)

diff --git a/.gitignore b/.gitignore @@ -1 +1,2 @@ .env +out diff --git a/cli.pl b/cli.pl @@ -8,6 +8,7 @@ use open qw(:std :encoding(UTF-8)); use LWP::UserAgent; use JSON::PP; +use Data::Dumper; if (!$ENV{SPOTIFY_TOKEN}) { die "SPOTIFY_TOKEN not set in environment\n"; @@ -19,18 +20,17 @@ if (!@ARGV) { my $user = $ARGV[0]; my $API = "https://api.spotify.com/v1"; +my $ua = LWP::UserAgent->new(); +$ua->default_header("Authorization" => "Bearer $ENV{SPOTIFY_TOKEN}"); sub get_playlists { - my $ua = LWP::UserAgent->new(); + my $limit = shift; + $limit //= 10000; 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"; @@ -39,16 +39,68 @@ sub get_playlists { foreach my $item (@{$j->{items}}) { push(@playlists, $item); } - if (!$j->{next}) { + if (!$j->{next} || scalar @playlists > $limit) { last; } - print("Paging: $url\n"); + print("Paging Playlists: $url\n"); $url = $j->{next}; } return @playlists; } -my @p = get_playlists(); -print($_->{name} . "\n") for @p; +sub describe { + my $p = shift; + my $pub = $p->{public} ? "Public" : "Private"; + my $collab = $p->{collaborative} ? "Collaborative" : "Personal"; + my $s = <<EOM; +# $p->{name} + +By $p->{owner}->{display_name} +$pub & $collab + +EOM + my $url = "$API/playlists/$p->{id}?fields=tracks.next,tracks.items(added_at,track.name,track.artists(name))"; + my $i = 1; + while (1) { + my $res = $ua->get($url); + if (!$res->is_success) { + print(Dumper($res)); + my $err = $res->decoded_content; + die "Failed to fetch playlist: $err"; + } + my $j = decode_json($res->decoded_content); + foreach my $t (@{$j->{tracks}->{items}}) { + (my $d = $t->{added_at}) =~ s/T.*Z$//; + my $fart = @{$t->{track}->{artists}}[0]->{name}; + $s .= sprintf( + "[%s] %-4d \"%s\" by %s\n", + $d, $i, $t->{track}->{name}, $fart, + ); + $i += 1; + } + if (!$j->{tracks}->{next}) { + last; + } + print("Paging Tracks: $url\n"); + $url = $j->{tracks}->{next}; + } + return $s; +} + +sub writep { + my $p = shift; + my $desc = describe($p); + (my $fname = $p->{name}) =~ s/\s/_/g; + $fname =~ s/\W//g; + open(my $fh, ">", "out/$fname.txt") or die $!; + print $fh $desc; + close $fh; +} + +my @playlists = get_playlists(); +foreach my $p (@playlists) { + print("Processing $p->{name}\n"); + writep($p); +} exit 0;