TITLE: I made a command line podcast grabber in Python DATE: 2018-03-26 AUTHOR: John L. Godlee ==================================================================== Pypodd I've been working on and off since around Summer last year, making a simplistic command line podcast catching app. I had a go with lots of other podcatchers: upodder, greg, podcatcher and others that I can't remember, but I found them to be just a bit overblown, and many had difficulty when RSS feeds were constructed with certain types of formatting. So while I was on trying to learn Python I set myself the task of writing a little app. [upodder]: https://github.com/m3nu/upodder [greg]: https://github.com/manolomartinez/greg [podcatcher]: https://github.com/doga/podcatcher In the end, it only took 120 lines of code, which I think is quite good, though it doesn't do anything fancy like let you store databases of played episodes, it just lists podcasts through a heirarchical menu system and lets you download them one at a time. #!/usr/local/opt/python/libexec/bin/python # Modules import feedparser import urllib import os import csv from progress.bar import Bar # Define system location variables destDir = os.environ['HOME'] + os.sep + "Downloads" + os.sep # Note trailing `os.sep` subsLoc = "subscriptions.txt" # e.g. subsLoc = os.environ['HOME'] + os.sep + "subscriptions.txt" # Define progress bar class for urllib.urlretrieve() class dlProg: def get(self, url, to): self.p = None def update(blocks, bs, size): if not self.p: self.p = Bar(to, max=size) else: if size < 0: self.p.update() else: self.p.goto(blocks * bs) urllib.urlretrieve(url, to, update) self.p.finish() # Import subscriptions list from csv containing [url, name] with open(subsLoc) as f: subs = csv.reader(f) subs = list(subs) # Split subs into URLs and titles urlList = [x[0] for x in subs] subList = [x[1] for x in subs] # Select a podcast to download, from list of subscriptions count_subs = 1 input_exit = 1 while input_exit != 2: # Terminate program if input_exit == 2 for i in subList: print(str(count_subs) + ") " + i) # Print list of podcasts - could convert to parsed feeds later count_subs += 1 input_subs = input("\nChoose a podcast [1-n]: ") # Take input input_subs = int(input_subs) # Convert input to integer index_subs = input_subs - 1 # For 0-base indexing # Parse chosen feed feedChooseList = [] # Create empty list feedChooseList.append(urlList[index_subs]) # Fill list with URL of chosen podcast feedList = [] # Create empty list for i in feedChooseList: feedList.append(feedparser.parse(i)) # Fill list parsed data from URL # Extract episode names from parsed feed nameList = [] # Create empty list for i in feedList[0]['entries']: # Fill list with names of episodes nameList.append(i['title']) # Extract episode links from parsed feed linkList = [] # Create empty list for i in feedList[0]['entries']: # Fill list with episode URLs linkList.append(i['enclosures'][0]['href']) # Select episode to download - most recent or other - menu 1 count_epi_1 = 1 optList = ['Most recent episode', 'Another episode'] # Create a list of options print("\nMost recent episode: " + nameList[0] + "\n") # Print name of most recent episode for i in optList: # Choose between most recent or other episode print(str(count_epi_1) + ") " + i) count_epi_1 += 1 input_epi_1 = input("\nChoose an episode to download: ") # Take user input input_epi_1 = int(input_epi_1) # Select an episode to download - menu 2 count_epi_2 = 1 count_epi_3 = 1 len_nameList = len(nameList) if input_epi_1 == 1: # Outer if statement, if user inputs 1 or 2, do stuff, otherwise, return to beginning print ("\nDownloading most recent episode") dlExt = ".mp3" dlName = nameList[0] dlFile = destDir + dlName + dlExt dlURL = linkList[0] dlProg().get(dlURL, dlFile) optList = ['Download more', 'Exit'] # Create a list of options for i in optList: # Give option to download more podcasts (return to main menu or exit print(str(count_epi_2) + ") " + i) count_epi_2 += 1 input_exit = input("\nFinished Downloading. Get more?") input_exit = int(input_exit) elif input_epi_1 == 2: for i in nameList: print(str(count_epi_2) + ") " + i) count_epi_2 +=1 input_epi_2 = input("\nChoose an episode to download: ") input_epi_2 = int(input_epi_2) - 1 if input_epi_2 <= len_nameList: # Inner if statement, If user inputs a valid episode number, do stuff, otherwise, try again dlExt = ".mp3" dlName = nameList[input_epi_2] dlFile = destDir + dlName + dlExt dlURL = linkList[input_epi_2] dlProg().get(dlURL, dlFile) optList = ['Download more', 'Exit'] # Create a list of options for i in optList: print(str(count_epi_3) + ") " + i) count_epi_3 += 1 input_exit = input("\nFinished Downloading. Get more?") input_exit = int(input_exit) else: raw_input("Invalid choice, press Enter to try again...") else: raw_input("Invalid choice, press Enter to try again...") So basically, it's just a set of if statements linked to the value of user input variables, all wrapped in a big while loop so it continues to return to the first level menu unless you tell it to exit. The structure goes like this, where each number refers to a menu requiring user input: 1. Choose a podcast to download │ └─2. Choose an episode to download, most recent or another │ ├─Most Recent │ │ │ └─Downloading most recent episode └─Another │ └─3. Choose a specific episode to download │ └─Download the specific episode ![Pypodd screenshot](https://johngodlee.xyz/img_full/pypodd/pypodd_scrot.png)