Search code examples
batch-filexcopyrobocopybatch-rename

Move video files from Pictures directory to Video directory


My photo import tool (Picasa) does a great job at importing photos and videos from my phone and camera. What I like is that it creates a subfolder under the Pictures directory based on the Photo Taken Date of each photo/video. So you end up with this structure:

C:\Pictures\2017-02-01\DSC_0001.jpg
C:\Pictures\2017-02-01\DSC_0002.jpg
C:\Pictures\2017-02-01\DSC_0003.mp4 <--- problem

The only problem is that it puts videos in this same structure under Pictures.

As such, I'd like to right a batch script to find and move all video files (.mp4, .avi, .mov) from the C:\Pictures directory to the C:\Videos directory, but also with the date subfolder.... i.e.

Move C:\Pictures\2017-02-01\DSC_0003.mp4 to C:\Videos\2017-02-01\DSC_0003.mp4

Note that the date subfolder may or may not exist under C:\Videos.

Also since these are large video files, and there are a lot of them, I'd prefer a process that actually does a move and not a copy then delete, for the sake of speed and disk space utilization as I am almost out of space (after re-organizing these files, I will be archiving off to a NAS).

Also prefer using RoboCopy, xcopy, or xxcopy as I have them and use them today on my machine. If massively easier using PowerShell scripting, I can learn that if it is easy to do.

Final Solution I used Mofi's answer, but enhanced it just a bit to add a function to calculate the directory string length

@echo off
setlocal EnableExtensions DisableDelayedExpansion

rem Define folder with the pictures which is never deleted.
set "PicturesFolder=D:\Users\Chad\PicturesTest"

rem get string length of source directory to later use in a substring type function
call :strlen PicturesFolderDirectoryLength PicturesFolder
echo PicturesFolderDirectoryLength = %PicturesFolderDirectoryLength%

rem Change the current directory to directory with the pictures.
cd /D "%PicturesFolder%"

rem Search recursive in this directory for video files with
rem file extension AVI, MOV, MP4 or MPG and move those files.
for /F "delims=" %%I in ('dir /A-D /B /S *.avi *.mov *.mp4 *.mpg 2^>nul') do call :MoveVideo "%%I"

rem Discard all environment variables defined in this batch code
rem and restore initial current directory before exiting batch file.
endlocal
goto :EOF

rem MoveVideo is a subroutine called with name of current
rem video file name with full path by the FOR loop above.

rem It first defines target path for video file depending on source path
rem by removing the backslash at end and concatenating C:\Videos with the
rem source path omitting the first 11 characters which is C:\Pictures.

rem Then the target directory structure is created with redirecting the
rem error message output by command MD to handle STDERR in case of the
rem target directory already exists to device NUL to suppress it.

rem Next the video file is moved from source to target folder with silently
rem overwriting an already existing file with same name in target folder
rem because of using option /Y. Remove this option if a video file should
rem be kept in pictures folder and an error message should be displayed in
rem case of a video file with same name already existing in target folder.

rem Last the source folder is removed if it is completely empty which means
rem it does not contain any file or subfolder. All parent folders up to the
rem pictures folder are also removed if each parent folder is also empty
rem after deletion of an empty folder.

rem The subroutine is exited with goto :EOF and execution of batch file
rem continues in main FOR loop above with next found video file.

:MoveVideo
set "SourcePath=%~dp1"
set "SourcePath=%SourcePath:~0,-1%"
ECHO SourcePath=%SourcePath%

CALL SET "SourceSubFolder=%%SourcePath:~%PicturesFolderDirectoryLength%%%"
ECHO SourceSubFolder=%SourceSubFolder%

set "TargetPath=D:\Users\Chad\VideosTest%SourceSubFolder%"
echo TargetPath=%TargetPath%

md "%TargetPath%" 2>nul
move /Y "%~1" "%TargetPath%\%~nx1" >nul

:DeleteSourceFolder
rd "%SourcePath%" 2>nul
if errorlevel 1 goto :EOF
for /F "delims=" %%D in ("%SourcePath%") do set "SourcePath=%%~dpD"
set "SourcePath=%SourcePath:~0,-1%"
if /I not "%SourcePath%" == "%PicturesFolder%" goto DeleteSourceFolder
goto :EOF

:strlen <resultVar> <stringVar>
(   
    setlocal EnableDelayedExpansion
    set "s=!%~2!#"
    set "len=0"
    for %%P in (4096 2048 1024 512 256 128 64 32 16 8 4 2 1) do (
        if "!s:~%%P,1!" NEQ "" ( 
            set /a "len+=%%P"
            set "s=!s:~%%P!"
        )
    )
)
( 
    endlocal
    set "%~1=%len%"
    exit /b
)

Solution

  • Here is a commented batch code for this file moving task with keeping directory structure.

    @echo off
    setlocal EnableExtensions DisableDelayedExpansion
    
    rem Define folder with the pictures which is never deleted.
    rem Note: ~11 in third line of subroutine MoveVideo must be
    rem       replaced by ~length of the folder path defined here.
    set "PicturesFolder=C:\Pictures"
    
    rem Change the current directory to directory with the pictures.
    cd /D "%PicturesFolder%"
    
    rem Search recursive in this directory for video files with
    rem file extension AVI, MOV, MP4 or MPG and move those files.
    for /F "delims=" %%I in ('dir /A-D /B /S *.avi *.mov *.mp4 *.mpg 2^>nul') do call :MoveVideo "%%I"
    
    rem Discard all environment variables defined in this batch code
    rem and restore initial current directory before exiting batch file.
    endlocal
    goto :EOF
    
    rem MoveVideo is a subroutine called with name of current
    rem video file name with full path by the FOR loop above.
    
    rem It first defines target path for video file depending on source path
    rem by removing the backslash at end and concatenating C:\Videos with the
    rem source path omitting the first 11 characters which is C:\Pictures.
    
    rem Then the target directory structure is created with redirecting the
    rem error message output by command MD to handle STDERR in case of the
    rem target directory already exists to device NUL to suppress it.
    
    rem Next the video file is moved from source to target folder with silently
    rem overwriting an already existing file with same name in target folder
    rem because of using option /Y. Remove this option if a video file should
    rem be kept in pictures folder and an error message should be displayed in
    rem case of a video file with same name already existing in target folder.
    
    rem Last the source folder is removed if it is completely empty which means
    rem it does not contain any file or subfolder. All parent folders up to the
    rem pictures folder are also removed if each parent folder is also empty
    rem after deletion of an empty folder.
    
    rem The subroutine is exited with goto :EOF and execution of batch file
    rem continues in main FOR loop above with next found video file.
    
    :MoveVideo
    set "SourcePath=%~dp1"
    set "SourcePath=%SourcePath:~0,-1%"
    set "TargetPath=C:\Videos%SourcePath:~11%"
    md "%TargetPath%" 2>nul
    move /Y "%~1" "%TargetPath%\%~nx1" >nul
    
    :DeleteSourceFolder
    rd "%SourcePath%" 2>nul
    if errorlevel 1 goto :EOF
    for /F "delims=" %%D in ("%SourcePath%") do set "SourcePath=%%~dpD"
    set "SourcePath=%SourcePath:~0,-1%"
    if /I not "%SourcePath%" == "%PicturesFolder%" goto DeleteSourceFolder
    goto :EOF
    

    This batch file also removes all folders in C:\Pictures which become empty after moving the video files. But it does not remove folders which were already empty on starting the batch file.

    For understanding the used commands and how they work, open a command prompt window, execute there the following commands, and read entirely all help pages displayed for each command very carefully.

    • cd /?
    • echo /?
    • endlocal /?
    • for /?
    • goto /?
    • if /?
    • md /?
    • move /?
    • rd /?
    • rem /?
    • set /?
    • setlocal /?

    Read also the Microsoft article about Using Command Redirection Operators for an explanation of >nul and 2>nul. In the main FOR loop the redirection operator > is escaped with caret character ^ to be interpreted as literal character on parsing FOR command line and later as redirection operator on execution of DIR command line by FOR.