3

I need a command that plays a random mp3 from a directory. So far I have tried

ls *.mp3 | shuf -n 1 | omxplayer

Every different player just acts like it has not received a filename and spits out the help. Thanks for the help!

12
  • Can you give us an example of some of the MP3 filenames you're trying to use? Perhaps spaces are breaking it
    – Thomas Ward
    Mar 3, 2017 at 1:26
  • 2
    Don't you mean ... | xargs omxplayer? Was it a typo or do you truely have no idea how command lines work in MS-DOS, Windows, Unix etc.?
    – AlexP
    Mar 3, 2017 at 1:31
  • omxplayer probably expects the filename as an argument rather than as standard input: try shuf -n 1 -ze *.mp3 | xargs -0 omxplayer Mar 3, 2017 at 1:32
  • 2
    Did you try the version with shuf -ze *.mp3 and xargs -0 that I suggested? That should be safe for filenames containing spaces and other weirdness. Mar 3, 2017 at 2:40
  • 1
    @Terrance xdg-open "$(ls *.mp3 | shuf -n 1)" works fine enough unless the filenames have weird characters - in which case steeldriver's suggestion to use NUL-delimited output should be used
    – muru
    Mar 3, 2017 at 15:00

3 Answers 3

3

Firstly, I dislike Bash. Piping paths to processes isn't so nice, and causes all sorts of weirdness when not done 'just so'. That being said, many of the things that you are trying to do in Bash that are not kind with working or operating can be done with (unfortunately) more code, but can work the way you want it to, in other languages.

So, being somewhat bored and interested in creating something for this, I went and wrote a (very rough) Python script that can do what you're looking for. It may look complex, but it works pretty well, and I've put comments wherever or explained this below.

NOTE: I have only tested this with VLC player and Rhythmbox on my system, and with xdg-open which opens the GUI's default handler for the given file. In my case, VLC is the default that xdg-open calls. If you are on a GUI and just want to use the default Media player for the MP3 file, use xdg-open for "player".

Package Requirements On Your System:

  • python (Python 2.6 or higher, but not Python 3)
  • python-dev (Python libraries of importance)

Script Installation Process:

Not really much work here. But to make it simpler, follow these steps:

  1. Create a bin folder in your home directory: mkdir /home/$USER/bin
  2. Change directory to the new 'bin' folder: cd /home/$USER/bin
  3. Create a file called randommp3. Copy-and-paste the code from the "Code/Script" section below into this file with a text editor. Save said file.
  4. Make the file executable: chmod +x /home/$USER/bin/randommp3
  5. Have fun, but note the following usage tidbits:
    • You have no choice but to specify what media player to use. oxmplayer would be what you would put in place of player when you execute the file.
    • If your music is not in /home/$USER/Music (where $USER is the currently logged in user), then you also have to specify the full directory path with the --dir argument (or one of its aliases as explained in the "usage" section below). If the folder path contains any spaces at all, you must wrap it in single quotes (for example, for the "My Music" directory in a given path, you would enter it as /path/to/My Music to the --dir argument).

Example execution:

Open a random MP3 file from the user's Music folder in their Home directory, in the GUI VLC Player

randommp3 vlc-wrapper

Open a random MP3 file from an external drive called "MusicDrive" mounted at Music Drive in the /media folder, in the media player called oxmplayer

randommp3 --dir '/media/Music Drive' oxmplayer

Usage

randommp3 [-h] [--dir DIRPATH] player

Open a random MP3 in the player of choice, or the default player

positional arguments:
  player                The executable name of the media player to open the
                        MP3 with. If none specified, uses the system default
                        player.

optional arguments:
  -h, --help            show this help message and exit
  --dir DIRPATH, --directory DIRPATH, --music-dir DIRPATH
                        The path to the directory where your music is stored.
                        If the path has spaces, wrap the entire path in
                        single-quotes ('/home/ubuntu/My Music/' for example).
                        If not specified, the current user's Music directory
                        in their /home/ folder is used.

Code: (or a link that you can save if you are really that lazy)

#!/usr/bin/python

import getpass
import subprocess as sp
import os
import glob
import random
import argparse

if __name__ == "__main__":
    # Parse arguments to the script
    argparser = argparse.ArgumentParser(description="Open a random MP3 in the player of choice, or the default player",
                                        add_help=True)
    argparser.add_argument('--dir', '--directory', '--music-dir', dest='dirpath', type=str,
                           default=str('/home/' + getpass.getuser() + '/Music'), required=False,
                           help="The path to the directory where your music is stored. If the path has spaces, wrap the "
                                "entire path in single-quotes ('/home/ubuntu/My Music/' for example). If not specified, "
                                "the current user's Music directory in their /home/ folder is used.")
    argparser.add_argument('player', type=str, help="The executable name of the media player "
                                                    "to open the MP3 with. If none specified, "
                                                    "uses the system default player.")

    # Using the above 'argparser' items, get the arguments for what we're going to be using.
    args = argparser.parse_args()

    # Gp to the directory your music is in.
    os.chdir(args.dirpath)
    mp3s = glob.glob('*.mp3')

    # Modify the directory path to make sure we have the trailing slash
    dirpath = args.dirpath
    if dirpath[-1] not in '/\\':
        dirpath += '/'

    # Actually open the MP3 file, and /dev/null to suppress output messages from the process.
    DEV_NULL = open(os.devnull, 'w')
    execpath = [args.player, '%s%s' % (dirpath, str(random.choice(mp3s)))]
    sp.Popen(execpath, stdout=DEV_NULL, stderr=DEV_NULL)
2
  • Piping paths to processes isn't so nice, and causes all sorts of weirdness when not done 'just so' I thoroughly disagree. Pipes one of the best things about bash. I cant see any "weirdness". One just has to understand the difference between passing arguments and stdin. Bash is awesome, because you can do the same thing you did with 50 lines in python with a one-liner (see Terrance's answer).
    – phil294
    Nov 27, 2017 at 14:18
  • @Blauhirn there are times that pipes just don't work for some software, which is why I said the above. And while Python is more... complex... it's actually quite useful for picking random MP3s to play and such.
    – Thomas Ward
    Nov 27, 2017 at 14:38
3

This command should work in bash. You might want to run it from being in the parent folder of where your MP3 files are at.

find . -type f -name '*.mp3' | shuf -n 1 | xargs -d "\n" omxplayer

or replace omxplayer with your favorite media player.

Or another command that works is using the xdg-open to use your default player like @muru has commented:

xdg-open "$(find . -type f -name '*.mp3' | shuf -n 1)"

NOTE: If you remove the -n 1 from the shuf, then it will play all the MP3 files in a shuffled order. But this requires using the actual player and not xdg-open. And it only works in the first command here. Just tested it.

0
0

Debian linux has a perl program called randomplay that plays *.mp3 and files in other audio formats from one or more specified directories. I've used it for years.

For example, in my top level music directory, the following plays a randomized list of songs from all given directories:

randomplay artist1 artist2 artist3

Since it is perl, I presume it will run on any linux system when the dependencies are installed. No idea if it works on other OSs.

EDIT Just re-read the question and it sounds like the person might just want to play one random song. In that case, the --tracks=n argument is useful:

randomplay --tracks=1 directory

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .