Solving simple problems
Tags: perl, music, scrobbling, lastfm
Published: 2021-05-21 13:02:25

---
title: Solving simple problems
published: true
description: Perl is a first-class programming language which is used to write complex applications. But sometimes, it's good to use it to solve simple problems too. 
tags: perl, music, scrobbling, lastfm
cover_image: https://dev-to-uploads.s3.amazonaws.com/uploads/articles/xrl2x36ldhvwm61o3iqv.png
---

I write a lot of Perl. Currently, I'm spending two days a week working for a client - maintaining an old Perl codebase that drives a successful financial business. On the other days of the week, I'm writing a large Dancer application that I hope to turn into a business in the future. But sometimes, it's fun to use Perl to solve simpler problems too. Here's how I spent fifteen minutes or so this morning.

I listen to music while I work. One of the joys of working from home is that I can fill the room with music and don't have to wear headphones. I tend to listen to a single artist for a couple of hours at a time. I'll just say "Hey Google, play music by [someone]" and listen until I fancy something different.

But it's easy to get into a bit of a rut. I've noticed that I've spent a lot of time listening to four or five artists and, therefore, ignoring all of the other artists I enjoy listening to. This morning I had an idea of how I could work round that.

I've been scrobbling most of my listening for about fifteen years. For those who don't know, "scrobbling" is the act of logging what you're listening to using an external service so that, over time, you build up an accurate picture of who you listen to. I use [Last.FM](https://last.fm) and you can see [what I've been listening to](https://www.last.fm/user/davorg/library) on their site.

Another page on the site shows [my scrobbles by artist for all time](https://www.last.fm/user/davorg/library/artists). From there, it's easy to spot the artists who have been receiving too much attention from me recently.

So I decided, I'd write a Perl program to solve this problem. This was the basic design:

* Scrape my "artists scrobbled" page to get a list of artists and the number of scrobbles
* Ignore anything with over a thousand scrobbles (as that's the artists I listen to too much)
* Ignore anything with fewer than five hundred scrobbles (as I'm not sure how much I like those artists)
* Pick an artist at random from the remaining list

It didn't take long to write. The [code is on GitHub](https://github.com/davorg/pickanartist) and I've reproduced it below.

```perl
#!/usr/bin/perl

use strict;
use warnings;
use feature 'say';

use HTML::TreeBuilder;

my $username = shift || 'davorg';
my $url = "https://www.last.fm/user/$username/library/artists";

my $tree = HTML::TreeBuilder->new_from_url($url);

my ($table) =  $tree->look_down(
  class => qr/\bchartlist\b/,
);

my @artists;

my @rows = $table->look_down(_tag => 'tr', class => qr/chartlist-row/);
for (@rows) {
  my $name = $_->look_down(_tag => 'td', class => qr/chartlist-name/);
  my $count = $_->look_down(_tag => 'span', class => qw/chartlist-count-bar-value/);
  my $x = $count->content->[0] =~ s/,//gr;

  next if $x >= 1000 or $x <= 500;

  push @artists, $name->look_down(_tag => 'a')->content->[0];
}

say $artists[ rand @artists ];
```

I used [HTML::TreeBuilder](https://metacpan.org/pod/HTML::TreeBuilder) because I had been reminded of its existence earlier in the week but, honestly, I'm not convinced it was the best choice. I might have a go at rewriting it using something like [Web::Scraper](https://metacpan.org/pod/Web::Scraper) at some point.

And as I'm writing this, I'm thinking "Doesn't Last.FM have an API? Shouldn't I have used that?" (Answer: [yes it does](https://www.last.fm/api) and yes you should - so that's another fix I should make in the future.)

But anyway, that's what I threw together in fifteen minutes this morning. It works, so I don't really have much incentive to do much to it (Oh, who am I trying to kid? Of course, I'm desperate to spend the next two weeks "improving" it!)

I didn't expect it to be useful to anyone else, so I didn't even bother tweeting about it. But before long I got [a tweet from @wantarray](https://twitter.com/wantarray/status/1395692432948355075) saying he'd taken the basic logic and used it as the basic of a program which uses [Audio::MPD](https://metacpan.org/pod/Audio::MPD) to actually play the music.

So I thought I'd blog about it because a) it turns out to be more useful than I thought and b) I wanted to share the joy of using a powerful programming language to solve a trivial problem in my life.

How do you use Perl to make your life better?

**Update:** I couldn't resist rewriting it to use the Last.FM API. It looks much nicer now.

```perl
#!/usr/bin/perl

use strict;
use warnings;
use feature 'say';

use Net::LastFM;

my $username = shift || 'davorg';
my $method   = 'user.getTopArtists';

my $lastfm = Net::LastFM->new(
  api_key    => $ENV{LASTFM_API_KEY},
  api_secret => $ENV{LASTFM_SECRET},
);

my $data = $lastfm->request_signed(
  method => $method,
  user   => $username,
);

my @artists;

for (@{$data->{topartists}{artist}}) {
  next if $_->{playcount} >= 1000;
  next if $_->{playcount} <= 500;

  push @artists, $_->{name};
}

say $artists[ rand @artists ];
```

Of course, you now need to register for a [Last.FM API key](https://www.last.fm/api/account/create).