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?

10
  • 2
    As far as I can see from the way the scripts are constructed, none of them will work with filenames that contain spaces Commented Jul 15, 2022 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 Commented Jul 15, 2022 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. Commented Jul 15, 2022 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). Commented Jul 15, 2022 at 20:48
  • Also see unix.stackexchange.com/a/335839/367454 Commented Jul 15, 2022 at 20:59

1 Answer 1

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 "$src" "$dst" && ((step++))

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

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

    # Notify the user
    if [[ step -eq 3 ]]
    then
        notify-send "Converted '${src##*/}'"
        ((success++))
    else
        notify-send "Failed converting '${src##*/}' at step $step"
    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.

2
  • 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. Commented Jul 16, 2022 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. Commented Jul 18, 2022 at 19:26

You must log in to answer this question.

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