1

I'm trying to learn (with no programming background) to create some custom bash scripts for converting selected files from Nautilus, but I hit an issue I can't understand.

For reference, this is a script that DOES work. It converts selected .MP4 files to .mkv, copies the time stamp and prints some feedback to the user.

#!/bin/bash

for i in $NAUTILUS_SCRIPT_SELECTED_FILE_PATHS do ffmpeg -i "$i" -movflags use_metadata_tags -c:v libx265 -crf 26 -preset slow -c:a aac -b:a 160k "${i%.}.mkv" && touch -r "$i" "${i%.}.mkv" && notify-send "Converted '$(basename "$i")'" || notify-send "Failed converting '$(basename "$i")'" done

notify-send "Conversion finished"

Now, this is a script that DOESN'T work. It should convert selected .m4a files to .mp3, add a cover image and some tags, copy the time stamp and give some feedback to the user.

#!/bin/bash

for i in $NAUTILUS_SCRIPT_SELECTED_FILE_PATHS do ffmpeg -i "$i" "${i%.}.mp3" && eyeD3 -a "Author" -A "Album" --add-image="cover.jpg":FRONT_COVER "${i%.}.mp3" && touch -r "$i" "${i%.*}.mp3" && notify-send "Converted '$(basename "$i")'" || notify-send "Failed converting '$(basename "$i")'" done

notify-send "Conversion finished"

When I run this one, I get multiple errors that say "Failed converting (a part of the path to the file)"... for some parts of the path to the file, like parts of folder and file names.

I'm not sure what I'm doing differently here. I'm using the same $NAUTILUS_SCRIPT_SELECTED_FILE_PATHS parameter, but it doesn't work the same in the second script.

As a reference, this other script, which is the same as the second one but applies to all the files in the folder, does work perfectly, so I'm sure the commands inside do do work.

#!/bin/bash

for i in .m4a do ffmpeg -i "$i" "${i%.}.mp3" && eyeD3 -a "Author" -A "Album" --add-image="cover.jpg":FRONT_COVER "${i%.}.mp3" && touch -r "$i" "${i%.}.mp3" && notify-send "Converted '$(basename "$i")'" || notify-send "Failed converting '$(basename "$i")'" done

notify-send "Conversion finished"

What am I missing? Can the $NAUTILUS_SCRIPT_SELECTED_FILE_PATHS only work with certain file types? Is the issue somewhere else?

  • 2
    As far as I can see from the way the scripts are constructed, none of them will work with filenames that contain spaces – Chris Davies Jul 15 '22 at 18:58
  • 1
    ... according to this NautilusScriptsHowto it's a newline-delimited list; so presumably it can be kludged to work in the case of filenames containing other whitespace characters by setting IFS suitably – steeldriver Jul 15 '22 at 20:02
  • @steeldriver that would make (some sort of) sense. It's a shame the file list couldn't have been passed as a "$@" type argument list to a called script, though. – Chris Davies Jul 15 '22 at 20:13
  • For start, the very long command inside the for can be broken up into shorter, easier to read lines with <space>\<newline> at the end (literal space and newline, not the bracketed text). – Vilinkameni Jul 15 '22 at 20:48
  • Also see https://unix.stackexchange.com/a/335839/367454 – Vilinkameni Jul 15 '22 at 20:59
  • Thanks for the pointers and suggestions! I'm not sure they address the issue, but I can use them to improve the scripts in general and see if that helps. – eldelacajita Jul 16 '22 at 21:13
  • @steeldriver Actually, adding IFS="$(printf '\n!')" at the beginning of the script makes the script work. If you want to add something along those lines as an answer, I could mark it as the correct one. Of course, the script could be improved in many other ways, but this is what I was trying to figure out today. – eldelacajita Jul 16 '22 at 22:38
  • I should probably save the default IFS value and reset it at the end of the script, right? – eldelacajita Jul 16 '22 at 22:49
  • @eldelacajita although it may work in your case, reading the names line-by-line using a while loop as proposed in this answer is almost always better for the reasons discussed here (in particular, "fixing" the IFS alone doesn't deal with potential glob characters). – steeldriver Jul 17 '22 at 13:17
  • @steeldriver Thanks, I'll take that into account and give that solution another try. – eldelacajita Jul 18 '22 at 19:25

1 Answers1

1

This is how I would rewrite the failing script. I cannot test it but the concern I have is that there's no clarity regarding the directory in which the script runs. Does cover.jpg really exist?

It would be worth adding a notify-send "$PWD" near the top to check that the script is running from the expected directory. If it's not, then perhaps the relevant directory can be inferred from the value being processed from $NAUTILUS_SCRIPT_SELECTED_FILE_PATHS (you might need to change "cover.jpg" to "${src%/*}/cover.jpg").

#!/bin/bash
count=0 success=0

Transform command line arguments (if provided)

[[ -z "$NAUTILUS_SCRIPT_SELECTED_FILE_PATHS" ]] && NAUTILUS_SCRIPT_SELECTED_FILE_PATHS=$(printf "%s\n" "$@")

Process each file in turn

while IFS= read -r src do # Target dst="${i%.*}.mp3"

# Primary conversion to mp3
step=0
ffmpeg -i &quot;$src&quot; &quot;$dst&quot; &amp;&amp; ((step++))

# Add album cover (if available)
if [[ step -eq 1 ]]
then
    if [[ -f &quot;cover.jpg&quot; ]]
    then
        eyeD3 -a &quot;Author&quot; -A &quot;Album&quot; --add-image=&quot;cover.jpg&quot;:FRONT_COVER &quot;$dst&quot; &amp;&amp; ((step++))
    else
        ((step++))
    fi
fi

# Reset the timestamp
if [[ step -eq 2 ]]
then
    touch -r &quot;$src&quot; &quot;$dst&quot; &amp;&amp; ((step++))
fi

# Notify the user
if [[ step -eq 3 ]]
then
    notify-send &quot;Converted '${src##*/}'&quot;
    ((success++))
else
    notify-send &quot;Failed converting '${src##*/}' at step $step&quot;
fi

# Count it
((count++))

done <<<"$NAUTILUS_SCRIPT_SELECTED_FILE_PATHS"

[[ count -gt 1 ]] && notify-send "Conversion finished ($success files of $count)"

exit $((count - success))

You could probably protect the notify-send calls with something like [[ -n "$DISPLAY" ]] && notify-send … but I can't be totally sure. This would then allow you to run the script from batch (at, for example) with command-line arguments.

Chris Davies
  • 116,213
  • 16
  • 160
  • 287
  • 1
    Wow, this blows my previous scripts out of the water. I will try it and see how it works. In any case, I'm already learning from it, so thanks a lot!

    Note: Where I wrote cover.jpg I usually put the full path to a file I have stored somewhere else. It's always the same file. Note 2: The script is always executed in the folder where the selected files are. I think that's how Nautilus scripts are supposed to work, but maybe I'm wrong.

    – eldelacajita Jul 16 '22 at 21:14
  • Followup: My first tries with this version didn't work. I'll try again with more time so I can understand what it does and why it fails. – eldelacajita Jul 18 '22 at 19:26