podget(7)
π podget β manual page (podget(7)), part 1 of 3 π
okay bestie, settle in, this is a long one but it's SO worth it π«Ά
β¨ NAME β¨
Podget β the simple tool that automates downloading of podcasts. no cap, that's the whole vibe π
π SYNOPSIS π
podget <options>
πΈ DESCRIPTION πΈ
So like, Podget is a simple podcast aggregator/downloader that's optimized for scheduled background jobs (i.e. cron). It's giving "set it and forget it" and honestly? iconic.
It features support for:
- Downloading podcasts from RSS and ATOM XML feeds. π₯
- Sorting the files into folders and categories. ποΈ
- Importing URLs from iTunes PCAST files and OPML lists. π
- Automatic M3U & ASX playlist creation. π΅
- Cleanup of old files. π§Ή
- Automatic UTF-16 conversion for feeds hosted on MS Windows Servers. πͺ
Here's the tea on how it actually works: Podget extracts the <enclosure> tags from the feed and then downloads the specified URL. β¨ But there is one exception where Podget will straight-up ignore <enclosure> tags, and that's when they're inside <podcast:liveItem> tags β because Podget is an aggregator and not a player, so it has not been optimized for live content. periodt. π
π OPTIONS π
-c <FILE>,--config <FILE>β Name of configuration file. π--create-config <FILE>β Create configuration file and exit. π-C,--cleanupβ Skip downloading and only run cleanup loop. π§Ό--cleanup_days <NUMBER>β Cleanup files older than<NUMBER>days. π--cleanup_simulateβ Simulate cleanup loop to see what files would be deleted. π (no actual deleting, just vibes)-d <DIRECTORY>,--dir_config <DIRECTORY>β Directory that configuration files are stored in. π--dir_session <DIRECTORY>β Directory that session files are stored in. ποΈ-f,--forceβ Force download of items from each feed even if they've already been downloaded. πͺ-h,--helpβ Display condensed help dialog. π-l <DIRECTORY>,--library <DIRECTORY>β Directory to store downloaded files in. π-n,--no-playlistβ Do not create M3U playlist of new items. π«-p,--playlist-asxβ In addition to M3U playlists, create ASX playlists. πΆ--playlist-per-podcastβ Create a playlist of new items for each podcast feed. π§-r <COUNT>,--recent <COUNT>β Download only the<COUNT>newest items from each feed. π--serverlist <FILE>β Use<FILE>as serverlist instead of default. π-s,--silentβ Run silently (for cron jobs). π€«-vβ Set verbosity to level 1.-vvβ Set verbosity to level 2.-vvvβ Set verbosity to level 3.-vvvvβ Set verbosity to level 4. π’--verbosity <LEVEL>β Set verbosity level (0-4).-V,--versionβ Display version. π·οΈ
π OPML List Options π
--import_opml <FILE or URL>β Import servers from OPML file or HTTP/FTP URL. π₯--export_opml <FILE>β Export serverlist to OPML file. π€
π¦ PCAST List Options π¦
--import_pcast <FILE or URL>β Import server from iTunes PCAST file or HTTP/FTP URL. π²
π§ CONFIGURATION FILES π§
By default, Podget relies on two configuration files. just two little guys running the whole show π₯Ή
podgetrcβ This is a file with most options for how Podget should run.
If it is required to run podget with different options for certain feeds, then additional configuration files can be created and used with the --config or -c option. When this option is run with a new filename that does not exist yet, the file is created with default options that can then be customized as necessary. β¨
serverlistβ This is a file of all the feeds that Podget should monitor and download from.
If you need to separate your feeds into multiple lists, then additional files can be created with the --serverlist option. When this option is run with a new filename that does not exist yet, the file is created with a default list of a single feed. Whenever a new list is created, Podget will download a single item from the single feed included by default to verify that everything is working. π
For a description of the options available for this file, please refer to the SERVER LIST CONFIGURATION section of this document. iykyk π
π USER CONFIGURATION DIRECTORY π
The first time a user runs podget, it will create a configuration directory. In this directory, it will install the default configuration files. π
Where this configuration directory is automatically placed is dependent upon the version of Podget that you used when you first ran it.
- For version 0.8.10 and before:
$HOME/.podget
- For later versions:
- If
$XDG_CONFIG_HOMEis set then it will be placed in:$XDG_CONFIG_HOME/podget - IF unset, then it will be placed in:
$HOME/.config/podget
- If
If a user wants to clean up their $HOME directory by moving their existing configuration directory to either of the new locations, it can be done but it is necessary to remember to remove the leading period so it is no longer a hidden directory. π«£
Example:
mv $HOME/.podget $HOME/.config/podget
These locations can be overridden by the use of the --dir_config or -d option when you run podget. π
π WHICH CONFIGURATION DIRECTORY IS USED π
Since there are at least three possible locations for the configuration directory then it is necessary to know which one podget will use. To keep things simple, Podget uses the first one it finds and tests in the following order:
$HOME/.podget$XDG_CONFIG_HOME/podget$HOME/.config/podget
This location testing is skipped by the use of the --dir_config or -d option. πββοΈ
π§Ό AUTOMATIC CLEANUP π§Ό
You can enable automatic cleanup with every run by configuring it in your podgetrc file. Simply set the following options:
# Autocleanup.
# 0 == disabled
# 1 == delete any old content
cleanup=1
# Number of days to keep files. Cleanup will remove anything
# older than this.
cleanup_days=7
However, some people prefer to run cleanup as a separate cron session. To do that, set the options in podgetrc to:
# Autocleanup.
# 0 == disabled
# 1 == delete any old content
cleanup=0
# Number of days to keep files. Cleanup will remove anything
# older than this.
cleanup_days=7
Then add something similar to this example to your crontab:
# Once a week on Sunday at 04:07AM
07 04 * * Sun /usr/bin/podget -C
π₯ MULTIPLE CONCURRENT SESSIONS π₯
Podget checks for sessions using the same core configuration file that may already be running when it starts and exits if any are found. This insures that any long running sessions are not interrupted by new ones. π
If you have feeds that require distinct configurations, then you can enable them to run simultaneously by using separate configuration files for each. Then if you have sufficient bandwidth, you can call them all at the same time. π€
Example Crontab configuration:
00 02 * * * /usr/bin/podget -c podgetrc-group1
00 02 * * * /usr/bin/podget -c podgetrc-group2
β SEQUENTIAL SESSIONS β
Sometimes, you have feed lists that use the same configuration but you wish to keep separate. There are two ways to handle this. π€
First, run then separately from crontab with sufficient time in between so they don't interfere with each other.
00 02 * * * /usr/bin/podget --serverlist RSS-Feeds
00 03 * * * /usr/bin/podget --serverlist ATOM-Feeds
The second option is to place them into a shell script so they are called sequentially and do not interfere with each other and then add it to your crontab.
#!/usr/bin/env bash
/usr/bin/podget --serverlist RSS-Feeds
/usr/bin/podget --serverlist ATOM-Feeds
π ENABLING DEBUG OUTPUT π
Debug output can be enabled in two ways. π΅οΈ
The first way is by uncommenting the DEBUG option in your podgetrc and setting it to '1'. However this way will not enable DEBUG until just over 1400 lines of script have run and when podgetrc finally is read. This is sufficient for most issues.
The second way is from the command-line and enables debug as early as possible. β‘
Simply execute podget like so:
$ DEBUG=1 podget -vvvv
You can enable other options as well if you need to but for debugging purposes, it is highly recommended that you enabled as much verbosity as possible. π£
π SERVER LIST CONFIGURATION π
By default, Podget uses serverlist for the default list of servers to contact. However you can configure the name with the config_serverlist variable in your podgetrc file.
Feeds are listed one per line in the serverlist file. βοΈ
Default format with category and name:
<url> <category> <name>
Alternate Formats:
- With a category but no name.
<url> <category>
- With a name but no category (2 ways).
<url> No_Category <name>
<url> . <name>
- With neither a category or name.
<url>
- URL Rules:
- A. Any spaces in the URL need to be converted to
%20
- A. Any spaces in the URL need to be converted to
- Category Rules:
- A. Must be one word without spaces.
- B. You may use underscores and dashes.
- C. You can insert date substitutions.
%YY%== Year%MM%== Month%DD%== Day
- D. Category disabling:
- With a name, the category must either be a single period (
.) or'No_Category'. - If the name is blank, the category can also be blank.
- With a name, the category must either be a single period (
- Name Rules:
- A. If you are creating ASX playlists, make sure the feed name does not have any spaces in it and the filename cannot be blank.
- B. You can leave the feed name blank, and files will be saved in the category directory.
- C. Names with spaces are only compatible with filesystems that allow for spaces in filenames. For example, spaces in feed names are OK for feeds saved to Linux ext partitions but are not OK for those saved to Microsoft FAT partitions.
- D. Feed names can be disabled by leaving them blank.
- Disable the downloading of any feed by commenting it out with a leading
#.
Example:
http://www.lugradio.org/episodes.rss Linux LUG Radio
Example with date substitution in the category and a blank feed name:
https://downloads.bbc.co.uk/rmhttp/downloadtrial/worldservice/summary/rss.xml News-%YY%-%MM%-%DD%
Example of two ways to do a feed with authentication:
http://somesite.com/feed.rss CATEGORY Feed Name USER:username PASS:password
http://username:password@somesite.com/feed.rss CATEGORY Feed Name
NOTE: The second method will fail if a colon (:) is part of the username or password. Both methods will fail if a space is part of the username or password. π
Common Options:
OPT_CONTENT_DISPOSITIONβ Attempt to get filename from the Content-Disposition tag that is part ofwget --server-response.OPT_DISPOSITION_FAILβ bestie this one is a team player, it only works when paired withOPT_CONTENT_DISPOSITION. What it does: any URL that failed to get a filename gets yeeted out of theCOMPLETEDlog, so it gets automatically retried next session. π Lowkey important caveat: if you add this to a feed you've already downloaded, you gotta go into theCOMPLETEDlog and manually delete the URLs for the problematic files yourself. On one feed this glow-up took filename problems from like 15% down to under 2% across 6 sessions. Those sessions can run back-to-back in one day or just ride along in your cron rotation. πOPT_FEED_ORDER_ASCENDINGβ okay so by default Podget assumes feeds list items newest β oldest (descending). This flips that for feeds that go oldest β newest. Fr fr, it does nothing noticeable if you're downloading every item. It only hits different on new feeds when you combine it with--recent [COUNT]. β¨OPT_FEED_PLAYLIST_NEWFIRSTβ most playlist options just make lists of the new stuff from this session. Not this one. This one creates or updates a full playlist of all items available for a feed, sorted newest β oldest based on the file's modification date/time. πOPT_FEED_PLAYLIST_OLDFIRSTβ same energy asOPT_FEED_PLAYLIST_NEWFIRST, except the playlist is ordered oldest β newest. π¦OPT_FILENAME_LOCATIONβ some feeds are so extra, they don't put the detailed filename in the FEED, they just rename the file on redirection π. This option handles that by grabbing the filename from the lastLocation:tag in the output ofwget --server-response.OPT_FILENAME_RENAME_MDATEβ for feeds that use one singular filename for every item, with the actual identity hidden in a long, incomprehensible string in the URL. These feeds used to be patched withFILENAME_FORMATFIX4, which appended that string to the common filename so each item got a unique name β but the names were giving unreadable. π This option is a whole new method: it prepends the file's last change date (the modification date) to the filename asYYYYMMDD_HHhMMm_<common-part>. Now your files are sortable and make a moderate amount of sense. Warning tho: it does not work for all feeds β on some feeds the last modification time for each file is just the time of download. That might be fine sometimes but it causes confusion when you're pulling more than one item at a time from a feed. πOPT_WGET_DEFUSERAGENTβ tells Wget to use its own default user-agent (normally formatted similar toWget/1.21.2) instead of Podget's default user-agent (Podget) or a custom agent you set inWGET_BASEOPTSin podgetrc.OPT_NO_CERT_CHECKβ disables wget SSL certificate verification. Super commonly used for feeds running self-signed certificates. πOPT_PREFER_IPv4orOPT_PREFER_IPv6β configures wget so that when a DNS lookup hands it several addresses to choose from, it connects to the specified family first. π
Examples:
http://somesite.com/feed.rss CATEGORY Feed Name OPT_PREFER_IPv4
http://somesite.com/feed.rss CATEGORY Feed Name OPT_PREFER_IPv6
http://somesite.com/feed.rss CATEGORY Feed Name OPT_WGET_DEFUSERAGENT
http://somesite.com/feed.rss CATEGORY Feed Name OPT_NO_CERT_CHECK
http://somesite.com/feed.rss CATEGORY Feed Name OPT_CONTENT_DISPOSITION
http://somesite.com/feed.rss CATEGORY Feed Name OPT_CONTENT_DISPOSITION OPT_DISPOSITION_FAIL
http://somesite.com/feed.rss CATEGORY Feed Name OPT_FILENAME_LOCATION
http://somesite.com/feed.rss CATEGORY Feed Name OPT_FILENAME_RENAME_MDATE
http://somesite.com/feed.rss CATEGORY Feed Name OPT_FILENAME_LOCATION OPT_FILENAME_RENAME_MDATE
http://somesite.com/feed.rss CATEGORY Feed Name OPT_FEED_ORDER_ASCENDING
http://somesite.com/feed.rss CATEGORY Feed Name OPT_FEED_PLAYLIST_NEWFIRST
http://somesite.com/feed.rss CATEGORY Feed Name OPT_FEED_PLAYLIST_OLDFIRST
π RSS Feed Options π
Okay so there are three options that are for RSS Feeds only β they are not supported for ATOM feeds, periodt.
The first two are about renaming downloaded files using the contents of the <TITLE> tag from the HTML, and the third one expands which tags Podget pulls content from. β¨
OPT_FILENAME_RENAME_TITLETAGβ version one, for feeds that put the<TITLE>tag before the<ENCLOSURE>tag. The majority of tested feeds that use<TITLE>tags follow this order. πOPT_FILENAME_RENAME_REVTITLETAGβ version two, for feeds that put the<ENCLOSURE>tag first, followed by the<TITLE>tag.OPT_RSS_MEDIACONTENTβ the third one! This lets Podget download content from<MEDIA:CONTENT>tags in addition to<ENCLOSURE>tags. π
Examples:
http://somesite.com/feed.rss CATEGORY Feed Name OPT_FILENAME_RENAME_TITLETAG
http://somesite.com/feed.rss CATEGORY Feed Name OPT_FILENAME_RENAME_TITLETAG OPT_FILENAME_RENAME_MDATE
http://somesite.com/feed.rss CATEGORY Feed Name OPT_FILENAME_RENAME_REVTITLETAG
http://somesite.com/feed.rss CATEGORY Feed Name OPT_RSS_MEDIACONTENT
To figure out if a feed uses <TITLE> tags and in which order, run this with the URL for the feed:
wget -O - http://somesite.com/feed.rss | sed -n -e :a -e 's/.*<enclosure.*url\s*=\s*"\([^"]+\)".*/URL 1/Ip' -e t -e "s/.*<enclosure.*url\s*'=\s*\([^i]\+\)'.*/URL \1/Ip" -e t -e 's/.*<title>\(.*\)<[/]title>.*$/TITLE 1/Ip' -e t -e '/\(<enclosure\|<title>\).*/I{N;s/ *0 /;T;ba}'
This spits out a list of lines starting with either TITLE or URL. The URL comes from the <ENCLOSURE> tag and the TITLE is, obviously, from the <TITLE> tag. π
On lots of feeds the first thing you'll notice is a few <TITLE> tags before the first URL even shows up. In that case, Podget uses the last TITLE it found, so the earlier ones get discarded. The part that actually matters is when we hit the first URL β from there you need to work out if that item's title came before or after the URL. Title first? Use OPT_FILENAME_RENAME_TITLETAG. Title second? Use OPT_FILENAME_RENAME_REVTITLETAG. π§ β¨
On some feeds, the downloaded filename won't have anything identifiable to tell you which TITLE goes with it. In those cases you may need to download a few items and literally listen to them to figure out which order they use. π
On some feeds, you'll find the downloaded filename and the TITLE are super similar. In those cases it's up to you, bestie β determine which one you prefer. π
On some feeds, the TITLE has very little in it to specify when it was recorded, and it might be useful to use the OPT_FILENAME_RENAME_MDATE option to add a date tag to each filename as it's converted. ποΈ
And on some feeds there will be a complete absence of TITLE lines. Those feeds just don't use the tag, so using either option won't produce any changes at all. π
π¦ Atom Feed Options π¦
The following options are available for advanced handling of Atom feeds.
ATOM_FILTER_SIMPLEβ enables filtering for just audio or video files from a feed. π§ATOM_FILTER_TYPE="type"β this one lets you filter way more precisely across all the varieties of types out there. You can limit downloads to a single type (example:"audio/mpeg") or to a few types (example:"(audio|video)/.*"for all audio and video types, OR"audio/.*"for all audio types). πATOM_FILTER_LANG="language"β if an Atom feed supports multiple languages for enclosures, this filters down to only the ones you want. Limit to one language (example:"en"for just English) or combine several supported languages to grab them all (example:"(en|es|fr)"to download files in English, Spanish and French). How the languages are defined may vary from feed to feed. π
Note: if you don't enable any of the ATOM_FILTER options on a feed with multiple enclosures per item, then when you run podget it will tell you the count per type or language to help you decide if you should enable the filters to reduce the number of files downloaded. π«Ά
Examples:
http://somesite.com/feed CATEGORY Feed Name ATOM_FILTER_SIMPLE
http://somesite.com/feed CATEGORY Feed Name ATOM_FILTER_TYPE="audio/mpeg"
http://somesite.com/feed CATEGORY Feed Name ATOM_FILTER_TYPE="(audio|video)/.*"
http://somesite.com/feed CATEGORY Feed Name ATOM_FILTER_LANG="en"
http://somesite.com/feed CATEGORY Feed Name ATOM_FILTER_LANG="(en|es|fr)"
http://somesite.com/feed CATEGORY Feed Name ATOM_FILTER_TYPE="audio/mpeg" ATOM_FILTER_LANG="en"
π§ HANDLING UTF-16 FEEDS π§
Some servers are out here serving their feeds in UTF-16 format rather than the way more common UTF-8. Not a vibe but we deal. π
To automatically convert these files, create a secondary serverlist in your configuration directory:
serverlist.utf16
And remember, bestie β change the name of the serverlist to match whatever you set it to with config_serverlist if you changed it. π
β EXAMPLE CRON JOB β
Once podget is running correctly, it's most useful if you run it from a cron job β that way the new episodes are ready to play or load onto a portable player and you don't have to sit there waiting for them to download. Iconic behavior honestly. π
To edit your crontab, do:
$ crontab -e
Then add one line similar to this example:
15 04 * * * /usr/bin/podget -s
This will run podget at 4:15 AM every day. β°
In some cases, you might need to add a few directories to your PATH variable so that Podget can find everything it needs.
Then the job might look like:
15 04 * * * PATH=/opt/local/bin:/usr/local/bin:$PATH /usr/bin/podget -s
π¦ INFORMATION AND DEBUG MESSAGES π¦
okay so sometimes when you're running Podget, you're like "bestie what is happening behind the scenes??" and you need a little more info to pinpoint what's causing a problem. Podget totally lets you do that β it can show you more of what's going on behind the scenes. β¨
For informational messages:
$ INFO= podget
INFO can be set to any value or none. It just matters that the variable is set.
By default, any informational message line will be prefixed with INFO --.
Debug messages get deeper into what is happening and are available in 5 levels.
By default Debug messages are disabled and are the equivalent of running:
$ DEBUG=0 podget
Higher Debug levels can be enabled and include these options.
$ DEBUG=1 podget
Level 1 Debug includes:
- Informational messages.
- Debugging messages (by default prefixed with
DEBUG --).
$ DEBUG=2 podget
Level 2 Debug includes:
- Informational messages.
- Debugging messages.
- Enable Bash Shell option for xtrace. The shell will print the expanded version of each command and arguments as they are run.
$ DEBUG=3 podget
Level 3 Debug includes:
- Informational messages.
- Debugging messages.
- Enable Bash Shell option for xtrace.
- Enable Bash Shell option for verbose. This will cause the script to print each line as they are read without expanding anything.
$ DEBUG=4 podget
Level 4 Debug includes:
- Informational messages.
- Debugging messages.
- Enable Bash Shell option for xtrace.
- Enable Bash Shell option for functrace. When enabled any traps on DEBUG and RETURN are inherited by shell functions, command substitutions and subshells.
- Enable Bash shell debug trap. Podget uses a very simple debug trap that causes each line as it is read to be printed with the line number it is on. This is effectively a slightly improved version of what the verbose option tells us.
π Special Handling for Debug messages π
The majority of the output from Podget is set to the STDOUT stream. However, when using Debug modes at level 2 or above, the additional messages are sent to the STDERR stream. For most uses, this is just fine. However if you wish to pipe the output to another command then it may be necessary to merge the two streams back together so they are displayed in the expected order. π«Ά
For example to pipe the output of Podget to less, you could run:
$ DEBUG=2 podget 2>&1 | less
π AUTHORS π
Dave Vehrs
That's a wrap, bestie β this is podget(7), dated 13 March 2025. Go forth and debug like the icon you are. π
β¨
π¦ where this page comes from
- debian trixie: podget 1.0.0-1 Β· GPL-3.0-or-later
- nixos 26.05: podget 1.0.0
- nixpkgs unstable: podget 1.0.0
- ubuntu resolute: podget 1.0.0-1 Β· GPL-3.0-or-later
- ubuntu stonking: podget 1.0.0-1 Β· GPL-3.0-or-later
- π girlified by deepseek-ai/DeepSeek-V4.1-Flash on : a language model's rewrite of the original, under its terms