« get me outta code hell

blog - My blog website - https://florrie.ed1.club
about summary refs log tree commit diff
path: root/site/posts/11-raspberry-pi-madness.md
diff options
context:
space:
mode:
Diffstat (limited to 'site/posts/11-raspberry-pi-madness.md')
-rw-r--r--site/posts/11-raspberry-pi-madness.md163
1 files changed, 163 insertions, 0 deletions
diff --git a/site/posts/11-raspberry-pi-madness.md b/site/posts/11-raspberry-pi-madness.md
new file mode 100644
index 0000000..098d3fd
--- /dev/null
+++ b/site/posts/11-raspberry-pi-madness.md
@@ -0,0 +1,163 @@
+
+    title: "Raspberry Pi madness"
+    permalink: '11-raspberry-pi-madness'
+    date: {m: 5, d: 26, y: 2017}
+    thumbnail: 'static/media/11-setup.png'
+    presentArt: true # ..this should probably be presentImage..
+    categories:
+    - 'text'
+    - 'dev'
+
+---
+
+# Raspberry Pi madness
+
+I got a Raspberry Pi, so, here's some rambling about it and what I've made
+with it.
+
+First things first - the Raspberry Pi is *weird.* It's just funny having a tiny
+little computer that can do pretty much anything (that isn't terribly
+computationally powerful). I guess it's not too surprising, since mobile
+devices are already way more powerful (and nearly smaller) than the Raspberry
+Pi; but this thing feels a bit different, maybe because I'm actually able to
+program it..? (But then there's Pythonista, too. Maybe it's the ability to
+SSH into the box sitting on my desk?)
+
+It's also just fun to look at. I took a picture of it:
+
+![Setup](static/media/11-setup.png)
+
+(That picture looks an awful lot like an album cover.)
+
+Although my new setup is a bit less crazy (I got rid of the HDMI output,
+keyboard and mouse).
+
+There's one distinct thing in that photo, though - the radio. I've got three
+reasons for using that radio, instead of the HDMI TV output:
+
+**Reason one:** I don't want it to rely on HDMI, since sometimes HDMI might
+not be available.
+
+**Reason two:** Radios give a nicer feeling. Having the radio speaker output
+sound seems more friendly than a gigantic TV (and/or a dedicated monitor)
+doing it.
+
+**Reason three:** I wasn't using the radio anyways.
+
+Okay, but, *what am I doing with it?*
+
+Short answer: it's playing my iTunes library.
+
+Long answer: it's downloading song files I have in my iTunes media folder and
+playing those. No files are stored on the Raspberry Pi (except for the
+currently playing track). I also made it be able to filter things by "group",
+which really just means by artist and (optionally) album.
+
+..Ah, who am I kidding? This intro's way too long. I just want to show how it
+actually works!
+
+---
+
+## Generating the Playlist
+
+The first thing we need to do is create a file containing all the songs and the
+URLs we can use to download them. I like using `python3 -m http.server` as my
+main static server, because it only takes that one command to use, so we'll try
+to parse the output of that.
+
+Thankfully, the format for directory listings with that server is relatively
+simple; every `<a>` on the page links to a file or a deeper folder. Since we're
+building a *tree* of the entire library (root -> artists -> albums), we'll need
+to navigate the directory recursively; to do that we just run the crawl-folder
+function on every `<a>` href-path that ends with `/`.
+
+Like I noted, the tree we end up with goes from the root folder, to a folder
+for each artist, and then a folder for each of an artist's albums.
+
+There's actually a setting in the iTunes preferences that does all of that
+sorting for us - under Advanced Preferences, "Keep iTunes Media folder
+organized". That's enabled by default, I think. How convenient.
+
+I wrote the program that crawls the `python3` server in a separate file from
+the main `play.js` script; `crawl-itunes.js`. In fact, it doesn't *require*
+iTunes in any way; really it'll generate a tree for any `python3` (or similar)
+server. (It probably won't work if the server gives parent-directory links, or
+if there's links; it isn't built to deal with potential infinite recursion,
+since that's not a problem in my case.)
+
+## Picking the Track
+
+Our playlist file essentially acts as a big listing of track titles and links
+to the HTTP download for respective files; we'll use it to pick our song.
+(That's what it's made for, after all!)
+
+The thing is, we want to randomly pick a track from all the tracks in our
+playlist file. But our playlist file is a tree. We have two options here:
+
+* Recursively pick a random file or sub-group, until we hit a file. Use that.
+
+* Flatten the tree, then pick a random item. Use that.
+
+I went with the second option. The actual code behind it is boring, obviously,
+so I won't bother going over it; but in summary we really are just flattening
+the tree and picking a random item.
+
+Also, now's a good time to mention the optional "group path" option I made for
+the program. If it's specified, the track-selector will only pick from tracks
+under the passed group. (Sub-groups are split by `/`; so, for example, you
+could make it only pick tracks from *Epic Battle Fantasy IV* by giving it the
+group path string `'Phyrnna/Epic Battle Fantasy IV'`.)
+
+## Downloading the Music
+
+Before we can actually play anything, we'll need to download the track we want.
+Just downloading the entire track before playing it works; the Raspberry Pi and
+the device with the iTunes library are on the same network, so there's no
+significant buffering.
+
+Our picked track playlist-item conveniently stores two pieces of information:
+the title of the song[\*] and the download link for it. Clearly we'll need the
+download link. It's just the HTTP URL we can fetch to download the track; so
+that's what we do.
+
+[\*] Really the text between `<a href="..">` and `</a>`; not the actual
+title of the track that's stored in the file's metadata. I'm too lazy to
+figure out how to get that, plus I think some formats don't even have any
+metadata of that sort.
+
+## Converting the Audio File
+
+Before we can actually play the file, we still need to do one thing.
+Realistically, our files aren't going to all be in a format the play command
+we're using will accept; we need to convert them to a standard format, like
+WAV, first.
+
+That's not actually difficult, though. We can use `avconv`[\*] to convert the
+downloaded file using a child process; that's just `avconv -y -i in out.wav`.
+(`-y` is there to ignore any "should this file be overwritten?" prompts.)
+
+[\*] Originally I'd thought to use `ffmpeg`, but apparently that doesn't
+actually exist as a proper package, and `avconv` is the more standard fork
+people use. But it looks like `ffmpeg` and `avconv` work basically the same
+way, at least to the user; so at least I didn't also have to learn a whole new
+command-line program!
+
+## Playing the Audio File
+
+Playing the audio file is as easy as running the `play` command. In fact,
+that's what we do!
+
+This step is actually that stupidly simple. It's literally just `play out.wav`.
+
+And then we loop back to picking another track!
+
+## What else can this do?
+
+I'd like to make a playlist file that somehow plays music from a YouTube
+channel that has tons of music uploads; SiIvaGunner and HeavyMetal Rocker1988
+come to mind. That shouldn't be too hard to do, but it would probably mean
+either making an in-between server that downloads and responds with the
+downloaded YouTube audio (*stupid!*) or making the program work by downloading
+YouTube audio, directly onto the Raspberry Pi (not stupid).
+
+Making it into an actual radio transmitter would be cool, too.