What’s in the box: Packaged but not streamed 2025 | R bloggers

What’s in the box: Packaged but not streamed 2025 | R bloggers

12 minutes, 40 seconds Read

[This article was first published on Rstats – quantixed, and kindly contributed to R-bloggers]. (You can report a problem with the content on this page here)


Want to share your content on R bloggers? click here if you have a blog, or here if you don’t.


I’m an anti-streaming music fan and instead stubbornly maintain a large music collection. This time of year, streamers receive an overview of their listens in a “packaged” report. Not wanting to miss this, I started creating my own annual review using R!

If you want to see a selection of my favorite albums of 2025, jump here. If you’re here for the R coding, read on!

I am aware that the audience for this post is small. We non-streamers are a dying breed, but also the number of people who took an XML snapshot of their iTunes/Music library to run this code last year might be zero.

To determine the number of plays in 2025, we need a snapshot of the library that is one year old. It’s then a matter of loading both into R, subtracting the number of songs played from last year’s snapshot from the current one, and then deleting all the songs with a difference of 0.

library(XML)
library(dplyr)
library(ggplot2)

# file paths for last year and this year XML files
lastyear <- "Data/Library_20241210.xml"
thisyear <- "Data/Library_20251203.xml"

# function to read xml file and convert to data frame
read_iTunesXML <- function(path) {
  df <- plyr::ldply(lapply(readKeyValueDB(path)$Tracks, data.frame))
  df$Play.Count <- replace(df$Play.Count,is.na(df$Play.Count),0)
  return(df)
}

# read in the music libraries
library_thisyear <- read_iTunesXML(thisyear)
library_lastyear <- read_iTunesXML(lastyear)

# merge the two libraries to get the correct play counts for this year
# we only need Persistent.ID and Play.Count from last year
sublibrary_lastyear <- library_lastyear[, c("Persistent.ID", "Play.Count")]
# merge
music_library <- merge(library_thisyear, sublibrary_lastyear, by = "Persistent.ID",
                         all.x = TRUE, sort = FALSE)
music_library$Play.Count.x <- replace(music_library$Play.Count.x,is.na(music_library$Play.Count.x),0)
music_library$Play.Count.y <- replace(music_library$Play.Count.y,is.na(music_library$Play.Count.y),0)
music_library$Play.Count <- music_library$Play.Count.x - music_library$Play.Count.y
# now get the tracks that were listened to in the last year
music_library <- music_library[music_library$Play.Count > 0, ]

# keep relevant columns only
music_library <- music_library %>%
  select(Name, Artist, Album, Genre, Year,
         Play.Count, Total.Time, Bit.Rate, Date.Added)

So now we have a data frame called music_library with the number of times each song has been played (in the past year). So let’s look at some basic facts about what was played.

## some basic facts about the library

# number of tracks listened to
nrow(music_library)
# total number of different artists listened to
length(unique(music_library$Artist))
# total play count
sum(music_library$Play.Count)
# total time that music has been played, in days
(sum(music_library$Total.Time * music_library$Play.Count) / 1000) / (60 * 60 * 24)

This gave me:

> # number of tracks listened to
> nrow(music_library)
[1] 22785
> # total number of different artists listened to
> length(unique(music_library$Artist))
[1] 2611
> # total play count
> sum(music_library$Play.Count)
[1] 26423
> # total time that music has been played, in days
> (sum(music_library$Total.Time * music_library$Play.Count) / 1000) / (60 * 60 * 24)
[1] 76.9794

Damn! 77 days of listening to music this past year! That’s >20% of my life listening to music…

# histogram of Years
music_library %>%
  ggplot(aes(x = Year)) +
  geom_histogram(binwidth = 1) +
  lims(x = c(1950,2026)) +
  labs(x = "Year", y = "Tracks") +
  theme_classic()
ggsave("Output/Plots/yearHistogram.png", width = 6, height = 4, units = "in", dpi = 300, bg = "white")

# same thing for library_this year
library_thisyear %>%
  ggplot(aes(x = Year)) +
  geom_histogram(binwidth = 1) +
  lims(x = c(1950,2026)) +
  labs(x = "Year", y = "Tracks") +
  theme_classic()
ggsave("Output/Plots/yearHistogram_thisyear.png", width = 6, height = 4, units = "in", dpi = 300, bg = "white")

This past year I’ve been listening to mostly new music (released in 2024 and 2025), with a few songs from previous years. Compared to the library, the preference for new songs played this year is quite high.

So what were the most played artists, albums and genres (before we get to the songs)?

# find the most played artists, albums, and genres
artist <- music_library %>%
  group_by(Artist) %>%
  summarise(Total_Plays = sum(Play.Count),
            n = n(),
            Mean_Plays = mean(Play.Count),
            Median_Plays = median(Play.Count),
            .groups = "keep") %>%
  filter(n > 5) %>%
  arrange(desc(Mean_Plays))

album <- music_library %>%
  group_by(Artist, Album) %>%
  summarise(Total_Plays = sum(Play.Count),
            n = n(),
            Mean_Plays = mean(Play.Count),
            Median_Plays = median(Play.Count),
            Year = median(Year),
            .groups = "keep") %>%
  filter(n > 2) %>%
  arrange(desc(Mean_Plays))

genre <- music_library %>%
  group_by(Genre) %>%
  summarise(Total_Plays = sum(Play.Count),
            n = n(),
            Mean_Plays = mean(Play.Count),
            Median_Plays = median(Play.Count),
            .groups = "keep") %>%
  filter(n > 15) %>%
  arrange(desc(Mean_Plays))

We now have three data frames, one for each thing, and I’m sorting by average counts, rather than total counts. This is because the number of tracks is different for each artist, album or genre. Everything is played once when I added it to the library, so if I add 3000 indie tracks and they have a total of 3000 plays, this should be ranked lower than the 300 reggae tracks that have a total of 600 plays.

> head(artist)
# A tibble: 6 × 5
# Groups:   Artist [6]
  Artist          Total_Plays     n Mean_Plays Median_Plays
1 200 Stab Wounds          96     9      10.7          12  
2 EYES                     97    10       9.7           9  
3 Miynt                    67    11       6.09          6  
4 Bnny                    145    25       5.8           5  
5 Turnstile               166    29       5.72          4  
6 Polygon Window           77    14       5.5           5.5

> head(album)
# A tibble: 6 × 7
# Groups:   Artist, Album [6]
  Artist          Album                          Total_Plays     n Mean_Plays Median_Plays  Year
1 200 Stab Wounds Manual Manic Procedures                 96     9      10.7          12    2024
2 EYES            SPINNER                                 97    10       9.7           9    2025
3 Turnstile       NEVER ENOUGH                           119    14       8.5           9.5  2025
4 Grouper         Dragging a Dead Deer Up a Hill          96    12       8             8    2007
5 Bnny            Everything                              88    14       6.29          5    2021
6 Miynt           Rain Money Dogs                         67    11       6.09          6    2025

> head(genre)
# A tibble: 6 × 5
# Groups:   Genre [6]
  Genre     Total_Plays     n Mean_Plays Median_Plays
1 Afrobeat           36    16       2.25            1
2 Hard rock          39    23       1.70            2
3 Dream Pop         628   381       1.65            1
4 Ambient           638   397       1.61            1
5 Reggae            122    76       1.61            1
6 Grunge            134    86       1.56            1

Finally, let’s look at the tracks. We can easily sort the music_library dataframe by play count, but (now that we’ve done this) it’s a bit boring because I’m an album listener. The songs in the top ten mainly come from my most played album. So let’s just take the best played song per artist/album to make it more interesting.

# order music_library by Play.Count
# take the first occurrence of artist album combination
music_library_unique <- music_library %>%
  arrange(desc(Play.Count)) %>%
  distinct(Artist, Album, .keep_all = TRUE)

and this gives us:

> # echo the top 10 most played tracks to the console
> music_library_unique %>%
+   select(Name, Artist, Album, Year, Play.Count) %>%
+   head(10)
                                Name          Artist                          Album Year Play.Count
1                I'll See You Around      Silver Sun                       Neo Wave 1998         21
2                  Hands of Eternity 200 Stab Wounds        Manual Manic Procedures 2024         16
3  Moving Day For the Overton Window            EYES                        SPINNER 2025         16
4                         Stay Hated      BENCHPRESS                     Stay Hated 2012         13
5                             August            Bnny                     Everything 2021         12
6                          SUNSHOWER       Turnstile                   NEVER ENOUGH 2025         10
7                              Orion        Mastodon                Medium Rarities 2020          9
8                      Wind and Snow         Grouper Dragging a Dead Deer Up a Hill 2007          8
9                            blazing    helen island                    last liasse 2024          8
10                      Sudden Storm     Ezra Furman             Goodbye Small Head 2025          8

So there you have it. I listened to Silver Sun’s I’ll See You Around 21 times. It’s because I tend to play this before I do a run (along with Stay Hated or lately Moving Day For the Overton Window). Highly recommended!

Hopefully this has given you some ideas on how to make your own “wrapped” with R.

Albums from 2025

I enjoy putting together my albums of the year. No idea if readers will find it useful, but I’ve benefited from album recommendations, so I’d like to pass them along. Additionally, I’d like to give a shoutout and link to the artists whose work I enjoyed this year. If you like something here, consider purchasing some merchandise or a release from one of the artists! Previous selections can be found here (2024, 2023, 2021).

SPINNER – EYES

Genre: hardcore [link]

Muscular hardcore from Denmark. I’ll honestly admit that I only looked into this after seeing it on a list and liking the cover and band logo. It turned out to be one of my favorite albums released this year.

NEVER ENOUGH – Tourniquet

Genre: hardcore

I was looking forward to this release from Turnstile and it did not disappoint. They played a great set at Glastonbury and I enjoyed their Tiny Desk Concert. I even checked out the visual album for this record. The addition of Meg Mills as a second guitar crunching into the mix has improved their sound quite a bit.

Rain Money Dogs – Miynt

Genre: lo-fi [link]

Bedroom doll from Sweden. Miynt is the alias of Fredrika Ribbing, who released this beautiful retro album this year (where retro is early 2000s and I feel old).

Shrunken Elvis – Shrunken Elvis

Genre: post rock [link]

An album of instrumental music with pure, simple guitar vibes. I read about this on the wonderful Tonearm website via Mastodon.

Goodbye Little Head – Ezra Furman

Genre: indie rock [link]

The opening track of this album, Grand Mal, is breathtakingly good. The vocals are pure indie rock, but are formulated as a rap song with lyrics that focus on the experience with epilepsy. The album is full of fragile tunes that are varied in style.

Phonetics on and on – Horse Girl

Genre: indie rock [link]

It seemed like I had this album on pre-order for months, so much so that I forgot about it when it finally came out. The album reminds me of Cub’s Betti-Cola with basic instrumentation and simple melodies.

Public Works and Utilities – Warrington-Runcorn New Town Development Plan

Genre: ambient, electronic [link]

I love the whole concept of WRNTDP for reasons I find difficult to describe. He was playing locally and I saw his performance. It was mainly songs from this album, which are more dance oriented than the previous releases which were more ambient in style.

Bugland – No joy

Genre: shoegaze [link]

I’ve been a big fan of Montreal’s No Joy since Wait To Pleasure, a modern shoegaze classic. This album is more psychedelic rock in style and again I saw her playing locally. She played a great (and very loud) set, one of the highlights of the year.

More – Pulp

Genre: rock

I wasn’t sure if I should include this. The album was a bit patchy, but in some places Pulp was back at its best. Spike Island is a great song. I saw them play in Birmingham and they were fantastic. I admired the fact that they actually got back together and released new material rather than just cashing in and re-releasing their old stuff (of course they did that too), but I appreciated what they did this year – 30 years after I saw them play the main stage at Glastonbury.

The bad fire – Mogwai

Genre: post rock [link]

I love what Mogwai does, even though they keep doing it record after record.

Touch – Turtle

Genre: post rock [link]

Another album that I had on pre-order for a long time. The band has gone through several line-up and sound changes, but in some places, like Axial Seamount, they sounded like the Tortoise of Millions Now Living Will Never Die.

McCartney, you’ll be fine – UNIVERSITY

Genre: noise rock [link]

I had to try out this band because they are from my hometown. I loved this record, which is a bit punk, almost screamo. The man on drums is a powerhouse. They released an EP later that year called YES, which features some of the most unhinged drumming I’ve heard in a long time. Just the song titles tell me that these are a bunch of friends having a good time and not taking themselves too seriously. I got major nostalgia vibes from this record, a fact that would horrify the youngsters in the band I’m sure!

Until the morning – Brian D’Addario

Genre: power pop [link]

Without a new album from The Lemon Twigs, I made do with this release from Brian D’Addario. It’s in the soft rock style. I’m amazed at how mature the songwriting is and the great retro production. Something for the music nerds among us.

Dim Probs – Norse Rhys

Genre: lo-fi [link]

There are several Super Furry Animals related releases on my list. The first is this album of acoustic sweetness from Gruff Rhys. I always enjoy his records, but this is his best in a while.

Under Strawberry Moons – Gulp

Genre: psychedelic folk [link]

An album full of spread folk with dreamy vocals and dubby bass by Guto Pryce (ex-SFA). Some instruments have a lounge, almost Latin atmosphere. A summer album I think.

The pattern speaks – SKLOSS

Genre: psychedelic rock [link]

This is heavy sludge rock freak territory with motory drums and mountains of fuzz guitars. Beautiful things. A recommendation from Steve Russell, I’m sure.

Sinister Grift – Panda Bear

Genre: psychedelic [link]

I like the layered vocals which I think are a trademark of Panda Bear. There are strong melodies and sunny vibes in abundance on this record.

Pink Silence – Cloth

Genre: indie rock [link]

I find this album difficult to categorize. It has an ’80s pop vibe in places, but at its core it’s an indie rock album.

Very human qualities – The Bug Club

Genre: Indie pop [link]

A recommendation from Sally Lowell. I enjoyed On The Intricate Inner Workings of the System and their earlier Pure Particles album. This release is wacky, humorous and reminiscent of The Lovely Eggs. They remind me of listening to John Peel’s radio show…

Pando – The Koolies

Genre: Electronics [link]

The other SFA related album on my list. I bought their earlier EPs and wasn’t entirely impressed. Still, I enjoyed this album. They produce great sounds and the production is perfect.

Reissues

I enjoyed these reissues, which came out this year:

  • Surfing on sine waves – Polygon window
  • Marquee Moon (Rhino High Fidelity vinyl reissue) – Television
  • Bound beans – everyone’s coffee beans

The remorse of the list makers

Oh, tomorrow is the last Bandcamp Friday of the year and I’m sure I’ll get my hands on something that I wish I could add to this list. But after putting these together for a few years, I realized it’s best not to obsess over them and just hit publish. Yeah, I didn’t put the Geese album on my list, even though it’s on everyone else’s. I’m sure there will be great albums that I’ve forgotten too. So be it! That was 2025.

The title of the post comes from “What’s In The Box (See Whatcha Got)” by The Boo Radleys from their album “C’mon Kids”. I seem to remember this song being about what’s in your record box, although I couldn’t find any confirmation online.


#Whats #box #Packaged #streamed #bloggers

Similar Posts

Leave a Reply

Your email address will not be published. Required fields are marked *