LinuxQuestions.org

LinuxQuestions.org (/questions/)
-   Linux - Software (https://www.linuxquestions.org/questions/linux-software-2/)
-   -   How to randomly "cd" for cli mplayer music files (https://www.linuxquestions.org/questions/linux-software-2/how-to-randomly-cd-for-cli-mplayer-music-files-4175458706/)

Dman58 04-18-2013 09:07 PM

How to randomly "cd" for cli mplayer music files
 
What's up LQ,

Dman here and I have a question. But 1st let me give a scenario.

I have been using Mplayer through Terminal to play my music files via cli in order to boost my cli knowledge. I generally "cd" to the path of whichever album I would like to play and type:

Example
Code:

mplayer -shuffle *.*m*
Which will play .mp3, .m4a, & wma

Problem is Me Really, I haven't got the insight in order to play the files as I would via a GUI application which tends to have tons of bells n whistles. For example randomly playing files that are generally in different locations.

Instead of copying specific files into a directory / playlist on the fly I would rather do 1 of 2 things. Either randomly "cd" to 1 of my many many music directories or recursively "cd" from: example - Artists main directory to a sub containing that same artists album.

I hope I stated that clearly.

Some might say just use the GUI but I think it can be accomplished via cli but with a little more effort. Plus I am just trying to gain more cli knowledge.

Is this the part where I start reading about for loops and while conditions or something or other?

chrism01 04-19-2013 02:27 AM

Yep :

Actually, bookmark these for ref (if you haven't already)
http://rute.2038bug.com/index.html.gz
http://tldp.org/LDP/Bash-Beginners-G...tml/index.html
http://www.tldp.org/LDP/abs/html/

That being said you can start from these 2 that talk about RANDOM
http://stackoverflow.com/questions/2...-a-bash-script
http://tldp.org/LDP/abs/html/randomvar.html

Basically store the dirnames in an array, then generate a RANDOM num in that range and cd to the array element of that number.

Dman58 04-19-2013 11:18 AM

Ok will do. Guess I have some homework for the weekend then.

Thanks chrism01!

mina86 04-19-2013 07:16 PM

Do you mean something like:
Code:

find -name \*.\*m\* -exec mplayer -shuffle {} +

schneidz 04-19-2013 07:26 PM

i found this on another members signature:
Code:


[schneidz@hyper ~]$ cat stuff/netcat.ksh
#!/bin/bash
PL=$(find /root/user/music -name "*.mp3")
NUM=$(echo $PL |wc -w)
{
while true; do
r=$(($RANDOM%$NUM))
s=$(echo $PL |cut -d ' ' -f$r)
echo "HTTP/1.0 200 OK\nContent-Type: audio/x-mp3stream\n\n"
dd if=$s bs=1024
done
} | nc -l -s address -p 8020

also look into the file command to find files of the type.

TobiSGD 04-19-2013 07:35 PM

I wouldn't use find for this, since even with the "-exec +" variant there is no guarantee that all found files will land in the mplayer command, if the number is large enough find will still split this into separate commands, so that you won'get real random playing.

I think this is a case for the shell functions, here pattern matching. I use Zsh, so I would use
Code:

mplayer -shuffle **/*.m*
to search for files that match the pattern *.m* in all sub-directories.
That should also work on Bash, but it may help to have a look at the Bash manuals.

rnturn 04-20-2013 04:17 AM

Quote:

Originally Posted by Dman58 (Post 4934479)
Instead of copying specific files into a directory / playlist on the fly I would rather do 1 of 2 things. Either randomly "cd" to 1 of my many many music directories or recursively "cd" from: example - Artists main directory to a sub containing that same artists album.

Seems clear enough. Sounds like you have a similar directory structure to mine: artist -> album [-> disc number, if needed] -> track (named as: tracknumber-title). (It is the natural way to store music files for transfer to my Cowon D2.)

If you're using Banshee, I think you can configure it to recognize the underlying directory/file structure. Check the "File Organization" section of the "Edit->Preferences->Source Specific" menu.

What I've been doing since the days when I used Alsaplayer (still my favorite but it doesn't seem to work any more) is to flatten the directory structure by creating symbolic links to the actual music files. To do this I wrote a Perl script that walks the tree of music files and created a symbolic link for each track in a subdirectory ($HOME/music/playlist) and then have the music player use that subdirectory as its "library". I use the album name (or the disk number for multidisc sets), the track number and track name in the name of the symbolic link. (Note: I recently ran into a flaw in my scheme where two albums wound up having a song by the same title as the same track number on their respective albums and I added the album name to the link name. A real rare bug that I might have fix would be if there turned out to be identically named tracks on the Nth disc of two (or more but that would be insanely rare) multidisk sets. I'd probably just insert a random number in the link name if there's a name clash.)

Even if Banshee doesn't need to see that flattened tree, it seems to work just fine. I used it with Amarok as well with no problems.

HTH...

--
Rick

David the H. 04-21-2013 03:51 PM

Quote:

Originally Posted by schneidz (Post 4935004)
i found this on another members signature: ...

I see a couple of problems with that script. Starting here:

Code:

PL=$(find /root/user/music -name "*.mp3")
...
s=$(echo $PL |cut -d ' ' -f$r)

Bad, bad, bad. Any file with whitespace in it would be impossible to handle. It really needs to be converted into an array instead.

It also shouldn't need to rely on external commands like wc and cut.

Code:


#!/bin/bash

# to safely set the array:
while IFS='' read -rd '' fname; do
    pl_array+=( "$fname" )
done < <( find /root/user/music -name "*.mp3" -print0 )

# Or bash's globstar could probably be used instead.
# just ensure there are no recursive symlinks first.
# shopt -s globstar
# pl_array=( **/*.mp3 )

num=${#pl_array[@]}

{  while true; do
        r=$(( RANDOM % num ))

        echo "HTTP/1.0 200 OK\nContent-Type: audio/x-mp3stream\n\n"
        dd if=${pl_array[r]} bs=1024
    done
} | nc -l -s address -p 8020

exit 0

Notice also that this is a truly random player, not shuffled, and will repeat songs. Nor is there any way to break out of the loop. One idea around this would be to remove duplicates and have it exit when the file list is empty.

Code:

{  while [[ -n ${pl_array[@]} ]]; do
        num=${#pl_array[@]}
        r=$(( RANDOM % num ))

        echo "HTTP/1.0 200 OK\nContent-Type: audio/x-mp3stream\n\n"
        dd if=${pl_array[r]} bs=1024

        unset pl_array[r]
        pl_array=( ${pl_array[@]} )  #re-indexes the array for the next pass

    done
} | nc -l -s address -p 8020


Dman58 04-25-2013 04:27 AM

Thank you all for your help, I appreciate the feedback.

@TobiSGD
Your response is actually more of what I was looking for. Very simple and to the point.

Code:

mplayer -shuffle **/*.m*
I didn't realize that the double asterisk would include sub-directories. That along with -shuffle makes my selection random enough for my tastes.

To everyone else Thank You very much I will experiment with those other suggestions as well in the near future. Most importantly read up on shell scripting, regular expressions, and everything else I need to better my understanding.

David the H. 04-25-2013 12:21 PM

** is the new (from v.4) bash globstar advanced globbing pattern, which I believe was copied over from ksh. You may have to enable it first with "shopt -s globstar". When followed by "/" it expands into a list of all subdirectories, allowing for recursive matching of file globbing patterns.

There is one weakness with it, however. If the file tree contains any directory symlinks that point back to a parent node it will get caught in a perpetual loop and chew up your memory. So be judicial in how you use it.

TobiSGD 04-25-2013 12:55 PM

Quote:

Originally Posted by David the H. (Post 4938772)
There is one weakness with it, however. If the file tree contains any directory symlinks that point back to a parent node it will get caught in a perpetual loop and chew up your memory. So be judicial in how you use it.

FWIW, this doesn't happen with Zsh.

David the H. 04-25-2013 03:12 PM

I'm sure it doesn't. Since it is new to bash, obviously not all the bugs have been worked out yet. It'll probably get fixed in time.

mina86 04-25-2013 04:53 PM

Quote:

Originally Posted by TobiSGD (Post 4935008)
I wouldn't use find for this, since even with the "-exec +" variant there is no guarantee that all found files will land in the mplayer command, if the number is large enough find will still split this into separate commands, so that you won'get real random playing.

I think this is a case for the shell functions, here pattern matching. I use Zsh, so I would use
Code:

mplayer -shuffle **/*.m*
to search for files that match the pattern *.m* in all sub-directories.

Are you sure this won't end up with the same problem? I'm reasonably sure that shell will refuse to run a command if the command line is too long (or if not shell, than kernel). Than again, Linux limits the number of arguments at 0x7FFFFFFF.

TobiSGD 04-25-2013 06:54 PM

If the number of files is large enough you will of course run into issues, but that would for me be the point to switch to a script to emulate shuffle without those limitations. The version with find you suggested does not circumvent those limitations, so using find in that way when the shell itself can do the job brings no advantages. FWIW, I just tried my solution on a directory with about 5300 MP3s and it worked without a problem. I am not sure how to test if find would already have splitted such a large number of files.

Dman58 04-27-2013 01:28 AM

Well it works just fine for me and I'm using it with 1000's of music files spread across a ton of directories.

LQ is the best! Thanks again.


All times are GMT -5. The time now is 04:10 AM.