2

In my .bashrc I have a function which I use to play random videos (not written below, just fyi), and another one for all media files, e.g.:

createmediafiles() {
find ~+ -type f -iregex '.*\.\(mp3\|wav\|ogg\|flac\|mp4\|mov\|avi\)' > ~/mediafiles.txt
find ~+ -type d -name VIDEO_TS >> ~+/mediafiles.txt
}

playmediafiles() { while true; do while read -r line; do shuf -n 1 | tee -a ~/played-log.txt | xargs -d "\n" mpv done < ~/mediafiles.txt done }

I want to add the VIDEO_TS line to createmediafiles, but in the playmediafiles function I want to add an IF statement, such that if the line shuffled to in mediafiles.txt is a VIDEO_TS then rather than using mpv to play a file, it will do:

tee -a ~/played-log.txt | xargs -d "\n" vlc --fullscreen

Piping in mediafiles.txt read the same way as it does with mpv.

How do I throw that in an IF statement with the condition being that the line ends in VIDEO_TS?

Ed Morton
  • 31,617
1toneboy
  • 441
  • Cramming all your code onto 1 line makes it harder for us to understand and so harder for us to help you so please don't cram all your code onto 1 line if you're going to ask anyone else to read it. I fixed it for you in this question. – Ed Morton Mar 26 '24 at 11:05
  • I think the code in playmediafiles is trying to generate a randomised/shuffled list of items to play. Which it sort of does but desperately inefficiently – Chris Davies Mar 26 '24 at 11:17
  • Please [edit] your question and show us example input and expected output. What is "the VIDEO_TS line"? What will those lines look like? – terdon Mar 26 '24 at 11:23
  • What's with ~+? Is it a typo or a construct I've just never seen before? – Chris Davies Mar 26 '24 at 11:24
  • 2
    @ChrisDavies It's a way of getting the current working directory via a tilde expansion. When used unquoted (to get tilde expansion), it is $PWD, and ~- is $OLDPWD. I believe it's not standard (it can also be used with a digit to access the other elements of the directory stack in both bash and zsh). – Kusalananda Mar 26 '24 at 11:36
  • @Kusalananda thanks for that, I've never seen it either. TIL... – Ed Morton Mar 26 '24 at 11:39
  • @ChrisDavies I would personally probably replace it with either "$PWD" or . depending on whether the full path is needed or not, just to avoid confusing readers, it this was my script. – Kusalananda Mar 26 '24 at 11:43
  • 1
    @Kusalananda I actually think it's a typo (which just happens to mean something apparently!) and should just be ~/ since that's what the OP uses everywhere else, including to access that file later. – Ed Morton Mar 26 '24 at 11:45
  • 1
    @EdMorton I didn't read it too carefully at first, but you may well be right. Of course, it would not matter if the createmediafiles function was always run from the user's home directory, but it would probably be creating mayhem (or at least unwanted files) if it wasn't. – Kusalananda Mar 26 '24 at 11:48

1 Answers1

1

I think you might be trying to do something like this:

playmediafiles() {
    local line cmd
while true; do
    line=$(shuf -n 1 ~/mediafiles.txt)
    case $line in
        *VIDEO_TS* ) cmd=( 'echo' 'vlc' '--fullscreen' ) ;;
        * )          cmd=( 'echo' 'mpv' ) ;;
    esac
    cmd+=( &quot;$line&quot; )
    printf '%s\n' &quot;$line&quot; &gt;&gt; ~/played-log.txt
    &quot;${cmd[@]}&quot;
done

}

or:

playmediafiles() {
    local line cmd
while true; do
    while IFS= read -r line; do
        case $line in
            *VIDEO_TS* ) cmd=( 'echo' 'vlc' '--fullscreen' ) ;;
            * )          cmd=( 'echo' 'mpv' ) ;;
        esac
        cmd+=( &quot;$line&quot; )
        printf '%s\n' &quot;$line&quot; &gt;&gt; ~/played-log.txt
        &quot;${cmd[@]}&quot;
    done &lt; &lt;(shuf ~/mediafiles.txt)
done

}

The first script loops forever calling shuf to select 1 line at a time at random from mediafiles.txt and store that line in the variable line.

The second script loops forever calling shuf to print the entire contents of mediafiles.txt in a random order, then has a second loop to read 1 line at a time from the shuf output and store that line in the variable line.

Both then test $line to see if it contains VIDEO_TS or not and populate the cmd array with the appropriate command plus arguments using cmd=( 'echo' 'vlc' '--fullscreen' ) or cmd=( 'echo' 'mpv' ). They then add the contents of line to the end of the array using cmd+=( "$line" ) and then print the contents of the array to played-log.txt and then execute the command stored in the array with "${cmd[@]}".

The only difference between the 2 is the first spawns a subshell to call shuf once per file to be played while the 2nd spawns a subshell to call shuf once for the whole of the input file and then read once per line to be played. The second one will probably run a bit faster but I doubt if you'll notice it or care since you're playing media between each line of input.

Remove the 'echo's when done testing to make sure it does what you want.

Ed Morton
  • 31,617
  • Part 1: Thanks for all the replies. I was in the mindset that writing in bashrc was writing just in the terminal, but I'll format better in future. I programmed in C at uni many years ago. I've never written much in bash. I might have written those functions devoid of understanding and by trial and error however ~+ was intentional, but there also was a typo where I appended for VIDEO_TS. None of this is really material. – 1toneboy Mar 27 '24 at 01:42
  • Part 2 The way while statements read is odd to me; I presume they read the whole file in at once. There are a couple of things I don't understand, even the line variable in my own code. Particularly I'm confused by the way shuf interacts. I mainly understand your first function, except for why you're cmd+=( "$line" ) and "${cmd[@]}". As for the second of your solutions, is this shuffling the whole file and then reading sequentially? i.e. done < <(shuf ~/mediafiles.txt) ? Why are there two < < Thanks – 1toneboy Mar 27 '24 at 01:42
  • For answers to all your questions read https://unix.stackexchange.com/a/169765/133219, https://man7.org/linux/man-pages/man1/shuf.1.html, https://mywiki.wooledge.org/BashFAQ/050#I.27m_constructing_a_command_based_on_information_that_is_only_known_at_run_time. and https://mywiki.wooledge.org/BashFAQ/001#Input_source_selection. Let us know if you have any followup question after reading those. – Ed Morton Mar 27 '24 at 02:13
  • Thanks, great links. I need to read the first one again more thoroughly when I have the time. So shuf -n 1 I take it only outputs one line at a time. The Input_source_selection link was very helpful. The last link though I found it hard to understand. So "${cmd[@]}" will execute arguments as a command? Strange that we still need to echo them. However, I still don't understand what cmd+=( "$line" ) is doing....thanks again – 1toneboy Mar 28 '24 at 03:30
  • You don;t need to echo them, the echo is there to show the commands that will be executed so you can verify it'll do what you want. Once you're happy that it will work as intended you'll remove the echos and then the real mpv or vlc will execute instead of being printed. That's what the final sentence in my answer means. – Ed Morton Mar 28 '24 at 09:56
  • Add set -x to the top of your script or run it using bash -x so you can see each line executing and what it does, but I added an explanation for both scripts including stating what cmd+=( "$line" ) does. – Ed Morton Mar 28 '24 at 10:05
  • 1
    Legend, thanks for the comprehensive explanation. – 1toneboy Mar 28 '24 at 11:40