Skip to content

Instantly share code, notes, and snippets.

@rjbs
Last active June 15, 2024 02:26
Show Gist options
  • Save rjbs/8bb921d529eb5dd52a497aaac4ddbed4 to your computer and use it in GitHub Desktop.
Save rjbs/8bb921d529eb5dd52a497aaac4ddbed4 to your computer and use it in GitHub Desktop.
#!/usr/bin/env perl
use v5.36.0;
use Digest::MD5 qw(md5_hex);
use Getopt::Long::Descriptive;
use IO::Async::Loop;
use JSON::XS;
use Net::Async::HTTP;
use Path::Tiny;
use URI;
my ($opt, $usage) = describe_options(
'%c %o',
[ 'target=s', 'find songs listened to by target' ],
[ 'listener=s', 'find songs not yet played by listener' ],
);
my $api_key = path('api-key.txt')->slurp;
my $secret = path('secret.txt')->slurp;
my $loop = IO::Async::Loop->new;
my $http = Net::Async::HTTP->new;
$loop->add($http);
sub djr ($res) {
decode_json($res->decoded_content(charset => undef));
}
sub uri ($param, $sign = 1) {
state $base = "https://ws.audioscrobbler.com/2.0/";
my $uri = URI->new($base);
my $str = q{};
for my $name (sort keys %$param) {
$uri->query_param($name => $param->{$name});
$str .= "$name$param->{$name}";
}
if ($sign) {
$str .= $secret;
my $sig = md5_hex($str);
$uri->query_param(api_sig => $sig);
}
return $uri;
}
my @tracks;
for my $user ($opt->target) {
my $top_tracks_res = $http->do_request(
uri => uri({
method => 'user.getTopTracks',
api_key => $api_key,
format => 'json',
user => $user,
period => '3month',
}, 0)
)->get;
my $top_tracks = djr($top_tracks_res);
my %got_artist;
TRACK: for my $track ($top_tracks->{toptracks}{track}->@*) {
unless ($track->{mbid}) {
# say "$track->{name} ($track->{artist}{name}) @ $track->{playcount}";
# say "^-- no mbid?!\n";
next TRACK;
}
my $debug;
if ($got_artist{$track->{artist}{mbid}}++) {
# Already saw this artist. I don't need a list of 69,105 Reznor
# masterpieces.
next TRACK;
}
my $seen = saw_track($track, $debug);
unless ($seen) {
say "$track->{name} ($track->{artist}{name}) @ $track->{playcount}";
}
}
}
sub saw_track ($track, $debug = 0) {
my $key = join q{--}, $track->{name}, $track->{artist}{name};
state %know;
return $know{$key} //= do {
my $uri = uri({
method => 'track.getInfo',
api_key => $api_key,
format => 'json',
username => $opt->listener,
track => $track->{name},
artist => $track->{artist}{name},
}, 0);
my $trackinfo_res = $http->do_request(
uri => $uri,
)->get;
my $info = djr($trackinfo_res);
if ($debug) {
print Dumper($info);
}
return 0 if $info->{error} && $info->{error} == 6;
return 0 if $info->{track}{userplaycount} == 0;
return 1 if $info->{track}{userplaycount} > 0;
die "!?";
};
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment