Unix/Linux Go Back    


Shell Programming and Scripting BSD, Linux, and UNIX shell scripting — Post awk, bash, csh, ksh, perl, php, python, sed, sh, shell scripts, and other shell scripting languages questions here.

Function to get the duration of all videos in a folder(s)

Shell Programming and Scripting


Reply    
 
Thread Tools Search this Thread Display Modes
    #1  
Old Unix and Linux 4 Weeks Ago   -   Original Discussion by zouhair
zouhair's Unix or Linux Image
zouhair zouhair is offline
Registered User
 
Join Date: Feb 2006
Last Activity: 23 April 2018, 2:33 PM EDT
Posts: 15
Thanks: 4
Thanked 0 Times in 0 Posts
Function to get the duration of all videos in a folder(s)

did this function to generate the duration of all the video files in a folder or multiple folders, it works fine for my use (I am no Guru as you may have noticed) but when I give it a lot of folders the calculation get a bit borked.


If any good soul had the energy to look at it and give pointers I will be grateful, but you really don't have to Linux




Code:
vidlength ()
{
    back=$(pwd)
    folder_length=
    total_folder_length=
    array=()

    # Look at the root of the folder
    # https://stackoverflow.com/a/23357277 How can I store find command result as arrays in Bash
    # $REPLY is the default variable when 'read' is not given one
    while IFS=  read -r -d $'\0'; do
        array+=("$REPLY")
    done < <(find . -maxdepth 1 \( -iname '*.mkv' -o -iname '*.mp4' -o -iname '*.avi' \) -print0)

    # exiftool -n -q -p '$Duration#' "${array[@]}" 2> /dev/null | awk '{sum += $0}; END{print sum}'                     GIVES TIME AS 78682.8
    # exiftool -n -q -p '${Duration;our $sum;$_=ConvertDuration($sum+=$_)}' "${array[@]}" 2> /dev/null| tail -n1        GIVES TIME AS 0:21:51:22
    
    # This command gives a result of '159' if the array is empty (2 minutes 39 seconds)
    total_folder_length=$(exiftool -n -q -p '$Duration#' "${array[@]}" 2> /dev/null | awk '{sum += $0}; END{print sum}') 

    # I have to add this because for wathever reason the last command fills len with the number 159 when it finds no video in the folder or when the array is empty
    if [[ "${total_folder_length%.*}" -eq 159 ]]; then
        total_folder_length=0
    fi

    counter=$(echo ${#array[@]})

    for folder in ./*; do
        #find . -maxdepth 1 \( -iname '*.mkv' -o -iname '*.mp4' -o -iname '*.avi' \)
        if [ -d "$folder" ]; then
            array=() # Empty the array between loops
            while IFS=  read -r -d $'\0'; do
                array+=("$REPLY")
            done < <(find "$folder" \( -iname '*.mkv' -o -iname '*.mp4' -o -iname '*.avi' \) -print0)
            
            # https://unix.stackexchange.com/a/170973 Way faster with exiftool
            # I have to add this because for wathever reason the last command fills len with the number 159 when it finds no video in the folder or when the array is empty
            folder_length=$(exiftool -n -q -p '$Duration#' "${array[@]}" 2> /dev/null | awk '{sum += $0}; END{print sum}')
            if [[ "${folder_length%.*}" -eq 159 ]]; then
                #len=$(echo "$len-159+$(exiftool -n -q -p '$Duration#' "${array[@]}" 2> /dev/null | awk '{sum += $0}; END{print sum}')" | bc)
                continue
            else
                total_folder_length=$(echo "$total_folder_length+$(exiftool -n -q -p '$Duration#' "${array[@]}" 2> /dev/null | awk '{sum += $0}; END{print sum}')" | bc)
            fi

            counter=$(echo $(echo ${#array[@]})+$counter | bc)
        fi
    done

    # Change it from 78682.8 to 0:21:51:22 https://unix.stackexchange.com/a/34033
    total=$(echo $total_folder_length | awk '{printf("%d:%02d:%02d:%02d\n",($1/60/60/24),($1/60/60%24),($1/60%60),($1%60))}')
    days=$(echo ${total} | awk -F ":" '{print $1}')
    hours=$(echo ${total} | awk -F ":" '{print $2}')
    minutes=$(echo ${total} | awk -F ":" '{print $3}')
    seconds=$(echo ${total} | awk -F ":" '{print $4}')

    if [[ "${days#0}" -gt 0 ]]; then
        #printf "The total duration found is:\n"
        printf "%d day(s) %02d hour(s) %02d minute(s) and %02d second(s) in %d videos\n" "${days#0}" "${hours#0}" "${minutes#0}" "${seconds#0}" "$counter"
    else
        if [[ "${hours#0}" -gt 0 ]]; then
            #printf "The total duration found is:\n"
            printf "%02d hour(s) %02d minute(s) and %02d second(s) in %d videos\n" "${hours#0}" "${minutes#0}" "${seconds#0}" "$counter"
        else
            #printf "The total duration found is:\n"
            printf "%02d minute(s) and %02d second(s) in %d videos\n" "${minutes#0}" "${seconds#0}" "$counter"
        fi
    fi

    cd "$back"
}

Sponsored Links
    #2  
Old Unix and Linux 4 Weeks Ago   -   Original Discussion by zouhair
RudiC's Unix or Linux Image
RudiC RudiC is offline Forum Staff  
Moderator
 
Join Date: Jul 2012
Last Activity: 22 May 2018, 5:11 PM EDT
Location: Aachen, Germany
Posts: 12,727
Thanks: 413
Thanked 3,912 Times in 3,598 Posts
That is quite confusing a script. And, what does "get a bit borked" mean? Incorrect? Slow? Crashes?

A few comments:
- you don't need an echo "command substitution" for a variable assignment in general.
- the repeated varn=$(echo ... | awk ... ) could be replaced by a read var1 ... varn <<< ... in what seems to be your bash version (which you, alas, don't mention)
- don't run exiftool with an empty array if the result is crooked, test the array upfront.
- your presumed bash version offers extended pattern matching of pattern-lists when the extglob option is set, mayhap eliminating the need for the find command.
- your presumed bash version offers the %()T format specifier:


Code:
printf "%(%T)T\n" 78682
22:51:22

The Following User Says Thank You to RudiC For This Useful Post:
zouhair (4 Weeks Ago)
Sponsored Links
    #3  
Old Unix and Linux 4 Weeks Ago   -   Original Discussion by zouhair
MadeInGermany's Unix or Linux Image
MadeInGermany MadeInGermany is offline Forum Staff  
Moderator
 
Join Date: May 2012
Last Activity: 22 May 2018, 3:36 PM EDT
Location: Simplicity
Posts: 4,079
Thanks: 351
Thanked 1,375 Times in 1,239 Posts
The classic approach is slow (run exiftool for each file) but safe:


Code:
total_folder_length=$(
  find . -maxdepth 1 -type f \( -iname '*.mkv' -o -iname '*.mp4' -o -iname '*.avi' \) |
  while IFS= read -r fname 
  do
    exiftool -n -q -p '$Duration#' "$fname"
  done |
  awk '{sum+=$0} END {print sum+0}'
)

Only -maxdepth 1 prints the start directory, so I added -type f

Last edited by MadeInGermany; 4 Weeks Ago at 05:17 AM.. Reason: added -type f
The Following User Says Thank You to MadeInGermany For This Useful Post:
zouhair (4 Weeks Ago)
    #4  
Old Unix and Linux 4 Weeks Ago   -   Original Discussion by zouhair
zouhair's Unix or Linux Image
zouhair zouhair is offline
Registered User
 
Join Date: Feb 2006
Last Activity: 23 April 2018, 2:33 PM EDT
Posts: 15
Thanks: 4
Thanked 0 Times in 0 Posts
Quote:
Originally Posted by MadeInGermany View Post
The classic approach is slow (run exiftool for each file) but safe:


Code:
total_folder_length=$(
  find . -maxdepth 1 \( -iname '*.mkv' -o -iname '*.mp4' -o -iname '*.avi' \) |
  while IFS= read -r fname 
  do
    exiftool -n -q -p '$Duration#' "$fname"
  done |
  awk '{sum+=$0} END {print sum+0}'
)

Much cleaner but as you said it is very slow when I run it on folders with more than 100 video files.

Thanks

---------- Post updated at 05:07 ---------- Previous update was at 04:47 ----------

Quote:
Originally Posted by RudiC View Post
That is quite confusing a script. And, what does "get a bit borked" mean? Incorrect? Slow? Crashes?

A few comments:
- you don't need an echo "command substitution" for a variable assignment in general.
- the repeated varn=$(echo ... | awk ... ) could be replaced by a read var1 ... varn <<< ... in what seems to be your bash version (which you, alas, don't mention)
- don't run exiftool with an empty array if the result is crooked, test the array upfront.
- your presumed bash version offers extended pattern matching of pattern-lists when the extglob option is set, mayhap eliminating the need for the find command.
- your presumed bash version offers the %()T format specifier:


Code:
printf "%(%T)T\n" 78682
22:51:22
Yup confusing is an euphemism, welcome to my brain, I have to deal with it on a daily basis.

Thanks for the pointers, I still need to learn more about the "best way" to do things.

And yes this function is used under BASH 4.4.13

Could you elaborate on read var1 ... varn <<< ...

Thanks a lot
Sponsored Links
    #5  
Old Unix and Linux 4 Weeks Ago   -   Original Discussion by zouhair
RudiC's Unix or Linux Image
RudiC RudiC is offline Forum Staff  
Moderator
 
Join Date: Jul 2012
Last Activity: 22 May 2018, 5:11 PM EDT
Location: Aachen, Germany
Posts: 12,727
Thanks: 413
Thanked 3,912 Times in 3,598 Posts
That is a variation of bash's "here documents": "here strings". This contruct evaluates the expression after the <<< and presents the result on stdin of the (here: read) command.
I don't know about exiftool nor do I have access to it, so simulated it with a cat of several files with integer numbers, trying to condense most of your script into the following three lines:


Code:
shopt -s extglob
IFS=: read DAYS HRS MIN SEC <<< $(printf "%(%j:%T)T" $(( $(cat *.@(avi|mp4|mkv) | tr '\n' '+' ) 0 )) )
echo $(( --DAYS)) $((--HRS)) $MIN $SEC
0 00 23 30

Here you have
- a here string to read the time elements from the result of printf
- a printf converting seconds to Day, Hour, Minute, and Second (using the "epoch" seconds; day and hour will start at 1 so have to be decremented for later use)
- an "extended pattern matching" for the video files in the working directory (use exiftool in lieu of cat for your purposes)
- shell "Arithmetic Expansion" $(( ... ))

The use of the extended pattern matching may be limited by sheer file count resp. file names' lengths, should they exceed the ARG_MAX or LINE_MAX system parameters...

Last edited by RudiC; 4 Weeks Ago at 06:33 AM..
The Following User Says Thank You to RudiC For This Useful Post:
zouhair (4 Weeks Ago)
Sponsored Links
Reply

Thread Tools Search this Thread
Search this Thread:

Advanced Search
Display Modes

Linux More UNIX and Linux Forum Topics You Might Find Helpful
Thread Thread Starter Forum Replies Last Post
Duration Calculation vikram3.r Shell Programming and Scripting 8 12-29-2017 02:26 PM
Copy duration of cp sepuku UNIX for Dummies Questions & Answers 2 10-09-2011 07:10 AM
Get password protected URL folder using PHP fopen function cgkmal Shell Programming and Scripting 2 11-03-2010 03:32 PM
duration calculation siba.s.nayak Shell Programming and Scripting 3 04-13-2010 03:27 PM



All times are GMT -4. The time now is 07:13 PM.