bashffmpeg

Read a text file line-by-line (each line as an array), run bash command with array elements, then loop to the next line in the text file


I'm using immich to manage my media library with photos and videos but appropriate video thumbnails are black or do not have an appropriate thumbnails for my family to view. As a test, I decided to manually recreate the thumbnails and then update appropriate thumbs files in the exact directory; replacing the auto-generated ones by Immich using ffmpeg. The following script works fine but one by one will take forever.

#!/bin/bash
file=(formula1 "aust_gp_00'23'41_2022_1858658849.mp4" f2dfse3-34gd-23ff-6hdd-p3h4kk/a3/10/a399-dj88-ah29 00:00:30.000)

# create jpeg + webp and replace existing
sudo ffmpeg -i /mnt/f1/"${file[0]}"/"${file[1]}" -ss "${file[3]}" -frames:v 1 /immich/app/thumbs/"${file[2]}"-preview.jpeg -y \
&& \
sudo ffmpeg -i /mnt/f1/"${file[0]}"/"${file[1]}" -ss "${file[3]}" -frames:v 1 /immich/app/thumbs/"${file[2]}"-thumbnail.webp -y

My goal is to put all the needed files in a text file use "readarry" to read each line as an array, use the appropriate index and then repeat for the next line. This is where I am stuck. How could I loop through each line where each line is a new file, keep the same indexes, and repeat? Anyone familiar with how to accomplish this or if there is a better way using bash? I was hoping to only use bash instead of python.

For example...

#files.txt
file=(formula1 "aust_gp_00'23'41_2022.mp4" f2dfse3-34gd-23ff-6hdd-p3h4kk/a3/10/a399-dj88-ah29 00:00:30.000)
file=(formula1 "belg_gp_00'13'31_2022.mp4" f2dfse3-34gd-23ff-6hdd-p3h4kk/q4/6/mhf-846d-zpyf 00:00:30.000)
file=(formula1 "melb_gp_00'05'11_2022.mp4" f2dfse3-34gd-23ff-6hdd-p3h4kk/b9/2/q3dd-0988-vr2t 00:00:30.000)

# genthumb.sh
#!/bin/bash
readarray -t lines < files.txt &&
  for line in "${!lines[@]}"; do
    sudo ffmpeg -i /mnt/f1/"${lines[0]}"/"${lines[1]}" -ss "${lines[3]}" -frames:v 1 /immich/app/thumbs/"${lines[2]}"-preview.jpeg -y \
    && \
    sudo ffmpeg -i /mnt/f1/"${file[0]}"/"${file[1]}" -ss "${file[3]}" -frames:v 1 /immich/app/thumbs/"${file[2]}"-thumbnail.webp -y
  done

Solution

  • bash doesn't have 2-dimensional arrays. readarray reads the entire file into a single array, each line is a single string element. So you can't use it to process each line as an array.

    Get rid of the file=(...) stuff in the file, just put the data without quotes. Then you can use a while read loop to read each field into a different variable, and substitute those into your commands.

    So change the file to:

    formula1 aust_gp_00'23'41_2022.mp4 f2dfse3-34gd-23ff-6hdd-p3h4kk/a3/10/a399-dj88-ah29 00:00:30.000
    formula1 belg_gp_00'13'31_2022.mp4 f2dfse3-34gd-23ff-6hdd-p3h4kk/q4/6/mhf-846d-zpyf 00:00:30.000
    formula1 melb_gp_00'05'11_2022.mp4 f2dfse3-34gd-23ff-6hdd-p3h4kk/b9/2/q3dd-0988-vr2t 00:00:30.000
    

    Then use

    while read -r name filename uid time; do
        sudo ffmpeg -i /mnt/f1/"$name"/"$filename" -ss "$time" -frames:v 1 /immich/app/thumbs/"$uid"-preview.jpeg -y </dev/null \
        && \
        sudo ffmpeg -i /mnt/f1/"$name"/"$filename" -ss "$time" -frames:v 1 /immich/app/thumbs/"$uid"-thumbnail.webp -y </dev/null 
    done < files.txt