Announcement

Collapse
No announcement yet.

BASH scripting help needed - How do I collect a file list and act on it?

Collapse
This topic is closed.
X
X
 
  • Filter
  • Time
  • Show
Clear All
new posts

    BASH scripting help needed - How do I collect a file list and act on it?

    I have begun (finally) a project to combine and catalog family video files from multiple sources - camcorder, cell phones, digital cameras, etc. My problem arises from that many of these are short but sequential clips, sometimes of different resolutions, and of different formats. My goal is files that are assembled into watchable lengths or uniform resolution with tags so we can tell what is what. I am working with literally 1000s of little files with the goal of several dozen or so - maybe a hundred - at the end.

    So far, my process is (and it works):
    1. Manually review, sort, and order clips into groups for combining.
    2. Use Handbrake to covert all the clips to mp4 while simultaneously re-sizing clips I want grouped together to they can be combined.
    3. Use the command-line utility MP4Box to string the clips together.
    4. Use puddletag to tag the files with content info (event, people, and places).
    5. Move them onto my media server for family viewing and sharing.


    The rub is step 3. MP4Box uses this format:

    MP4BOX -cat file_one.mp4 -cat file_two.mp4 -cat file_three.mp4... ad nausium ... -new new_file.mp4

    This is fine except I'm combining DOZENS of files at a time with names like 100_20130704.mp4. The typing is killing me. The upshot is MP4Box is great and reliably combines the files and does so very quickly. I've tried other ways to combine video files and none are as stable in operation as MP4Box has been. Point is - I'm not looking for a new process, I just want to automate the list of filenames into the MP4Box command.

    At one point I started using this to rename the files after segregating them into folders that contain a single group that I want to merge:
    a=1; for i in *.jpg; do new=$(printf "%02d.jpg" "$a"); mv -i -- "$i" "$new" let a=a+1; done

    This at least gave me a list of files as 01.mp4, 02.mp4, 03.mp4, etc. so I could re-use the previous MP4BOX command after editing it so a little bit.

    What I'd REALLY like is a way to run the command on the directory listing without manually listing the files and ultimately have a service menu that would let you select a group of files to combine. I'm willing to allow the files to be combined in alphabetical order since I'm manually reviewing them anyway, but file date ordering as a option would be nice too.

    I'd have to be able to create a list, then insert it into the MP4Box command with "-cat" in front of each filename and have the new file name at the end.

    My thought currently is to dump the file list to a text file, use sed to insert " -cat " before each file name and remove the carriage returns so it's a single line, insert "MP4Box" at the front of the line and " -new " and a prompted file name at the end and then execute it.

    Any better ideas or amazing suggests to do this well?

    Please Read Me

    #2
    This could be a starting point:
    Code:
    #!/bin/bash
    
    videos=$(ls *.mp4)
    
    for file in ${videos[@]}
    do    
    echo ${file}
    list=${list}" -cat "${file}
    done
    
    echo ${list}
    MP4BOX ${list} -new new_file.mp4
    Notes:
    - Combines .mp4 files in current working directory to new_file.mp4
    - Echo lines are there for some verbosity, not really necessary
    - Currently uses "ls" to get file list, you could use "find" or something else if you need more control
    - Not a complete solution yet, as it's kind of hard to tell what exactly are your needs and demands, but perhaps you can expand on it on your own
    - Should be usable in a service menu with selected files or a directory with a few changes
    Last edited by kubicle; Nov 03, 2017, 09:35 AM.

    Comment


      #3
      That was quick and Awesome! You're my hero! This should be easy to work into what I need at the script level.

      I think a service menu could pass a list directly to a script, but I'd have to test ordering - like does Dolphin deliver file names in the order selected or some other.

      Please Read Me

      Comment


        #4
        Originally posted by oshunluvr View Post
        I think a service menu could pass a list directly to a script
        Sure, you could also use a service menu to pass a directory and then act on files on that directory, whichever you prefer (or you could use both as separate actions)

        Note that parsing "ls" output is generally a bad idea (though it should work most of the time), I used it because it would be fairly simple to sort the files by mtime if you prefer (using "ls -tr"), but it would be safer to use (for example) echo or globbing directly in the for loop.

        So either:
        Code:
        #!/bin/bash
        
        videos=($(echo *.mp4))
        
        for file in ${videos[@]}
        do    
        list=${list}" -cat "${file}
        done
        
        MP4BOX ${list} -new new_file.mp4
        or just:
        Code:
        #!/bin/bash
        
        for file in *.mp4
        do    
        list=${list}" -cat "${file}
        done
        
        MP4BOX ${list} -new new_file.mp4
        (no need to set the videos array)

        Comment


          #5
          Example for the "directory" service menu (this relies on file name sorting order matching the order of the videos):

          service menu desktop file
          $HOME/.local/share/kservices5/ServiceMenus/mp4mergedir.desktop
          Code:
          [Desktop Entry]
          Type=Service
          X-KDE-ServiceTypes=KonqPopupMenu/Plugin
          MimeType=inode/directory;
          Actions=mergeFilesinDir;
          
          [Desktop Action mergeFilesinDir]
          Exec=/usr/local/bin/mp4merge %f
          Icon=video-mp4
          Name=Merge mp4 files in Directory
          Comment=Merge using MP4BOX, order based on file name sorting
          script
          /usr/local/bin/mp4merge:
          Code:
          #!/bin/bash
          
          cd $1
          newname=${PWD##*/}
          for file in *.mp4
          do    
             list=${list}" -cat "\"${file}\"
          done
          
          MP4BOX ${list} -new "${newname}.mp4"
          Names the merged mp4 based on the directoryname instead of "new_file.mp4"

          EDIT: improved handling of file names with spaces
          Last edited by kubicle; Nov 04, 2017, 02:48 AM.

          Comment


            #6
            Thanks a lot, I'll get those to work this weekend!

            Please Read Me

            Comment

            Working...
            X