Session 2 of 6

Songs from the SD Card

Read the SD card to discover what songs are available, then build your track list automatically.

🎯 By the end of this lesson you will be able to…
πŸ” Recall from Lesson 1

In Lesson 1 you created Track objects by hand and called add_track() for each one. That works, but what if the SD card has 50 songs? You would need 50 lines of code just for setup! This lesson shows you how to do all of that automatically.

Part 1 β€” Listing the files on the SD card

The pypod module provides a helper called list_music_files(). Call it and it returns a Python list of filenames β€” one for every .mp3 file on the SD card:

from pypod import list_music_files

files = list_music_files()
print(files)

# Example output:
# ['Bohemian Rhapsody (Queen).mp3',
#  'Never Gonna Give You Up (Rick Astley).mp3',
#  'Wonderwall (Oasis).mp3']

Under the hood this uses a standard Python function called os.listdir() β€” you will see that in later projects. For now, list_music_files() is all you need.

Part 2 β€” Taking a filename apart

Every filename follows the same pattern: Song Title (Artist).mp3. We need to pull it apart to get the title and artist separately.

Let's look at the pieces step by step:

  1. Remove the .mp3 extension. A string is a sequence of characters. We can take a slice of it using square brackets: filename[:-4] means "everything except the last 4 characters".
    filename = "Wonderwall (Oasis).mp3"
    stem = filename[:-4]       # "Wonderwall (Oasis)"
    
  2. Find the opening bracket. rfind("(") searches the string from right to left and returns the position (index) of the last (.
    position = stem.rfind("(")  # 11  (in "Wonderwall (Oasis)")
    
  3. Slice the string at that position. Everything before the bracket is the title; everything between the brackets is the artist.
    title  = stem[:position].strip()       # "Wonderwall"
    artist = stem[position + 1 : -1].strip() # "Oasis"
    
    πŸ“

    stem[position + 1 : -1] skips the ( at the start and the ) at the end. strip() removes any extra spaces at the edges.

Part 3 β€” Putting it in a function

You are going to do the same steps for every filename. Any time you need to repeat the same set of steps, a function is the right tool. Write the logic once; call it as many times as you need.

A function that takes a filename and returns both the title and the artist as a pair (called a tuple) looks like this:

def parse_filename(filename):
    """Given a filename like 'Wonderwall (Oasis).mp3',
    return ('Wonderwall', 'Oasis')."""
    stem     = filename[:-4]
    position = stem.rfind("(")
    title    = stem[:position].strip()
    artist   = stem[position + 1 : -1].strip()
    return title, artist   # returning two values at once

# Using the function:
t, a = parse_filename("Wonderwall (Oasis).mp3")
print(t)  # Wonderwall
print(a)  # Oasis
πŸ’‘ Returning two values

return title, artist packages both values into a tuple. On the receiving end, writing t, a = parse_filename(...) unpacks them automatically β€” t gets the title, a gets the artist. This is called tuple unpacking.

Part 4 β€” Looping over all filenames

A for loop lets you run a block of code once for every item in a list. Combine that with your new function and you can process every file automatically:

files = list_music_files()

for filename in files:
    print(filename)      # runs once per filename in the list

Part 5 β€” Building and displaying the full track list

Now put it all together. For each filename: parse it, create a Track, and call add_track():

main.py
from pypod import Track, add_track, list_music_files, music_path, start

def parse_filename(filename):
    """Return (title, artist) from a filename like 'Song (Artist).mp3'."""
    stem     = filename[:-4]
    position = stem.rfind("(")
    title    = stem[:position].strip()
    artist   = stem[position + 1 : -1].strip()
    return title, artist


for filename in list_music_files():
    title, artist = parse_filename(filename)
    track = Track(
        title     = title,
        artist    = artist,
        file_path = music_path(filename),
    )
    add_track(track)


start()
  1. Add the parse_filename function to your main.py.
  2. Replace your hand-written tracks from Lesson 1 with the for loop above.
  3. Run the code β€” the player should now list every .mp3 file from the SD card automatically.
  4. Try adding a new MP3 to the SD card (ask your teacher to copy one on), then restart the device. Does it appear without you changing any code?
πŸ† Challenge