Snapshot manipulation?

framednlv

Getting the hang of it
Mar 17, 2014
253
69
Does anyone have a way to manipulate snapshot JPG's with VB script or BAT file? They are buried deep into subfolders and I would like to rename using the date and time file was created & move them to a different folder and delete the old folders.

Chris
 
Last edited by a moderator:
You'd have to be more specific. VB / Batch scripting is not my specialty but if it is simple enough I could whip up a little command-line application to do it.
 
It would need to search a specific folder and sub folders for all jpg files, then rename or save or move (move preferred) to a single folder using the creation date (YYYMMDDHHMMSS) + .jpg for the file name.

Attached is a sample listing of the files saved for motion snapshots.

I was able to find a couple of VBS script that came close but not quite. One would work if all the files were in one folder. The other one worked for all the sub directories but didn't change the name or remove the directories.


Thanks,
Chris
 

Attachments

I built a command line application for you which does what you asked for (more or less). Let me know if it works as intended or if you need a change.

Update: Now on github: bp2008/ImageOrganizer

Usage (this shows if you run the program without any arguments):

Code:
Copies files from the source directory and child directories,
consolidating them in the target directory and renaming the
files to the format yyyyMMddHHmmssfff + .extension where the
timestamp is the last modified date's year, month, day, hour,
minute, second, millisecond.

        Note: Files will not be overwritten.  If a file
        already exists, the new file will have a space and an
        identifying number will be appended to the timestamp
        in the file name (e.g. 20140408010101000.jpg and
        20140408010101000 2.jpg and 20140408010101000 3.jpg)

Usage: ImageOrganizer source target [/C] [/M] [/E:Extension1[/Extension2][/Extension3]...]

        /C      Names the files based on creation time instead of modified time.
        /M      Moves the files instead of only copying them.
        /E:     Specify the extension(s) of the files to move or copy.
                If unspecified, only jpg files will be affected.

                Example: /E:jpg/jpeg/bmp/png/gif/webp/raw


C# Source code targetting .NET 3.5 Client Profile:
Code:
using System;
using System.Collections.Generic;
using System.Text;
using System.IO;

namespace ImageOrganizer
{
    class Program
    {
        static void Main(string[] args)
        {
            try
            {
                if (args.Length >= 2)
                {
                    DirectoryInfo diSource = new DirectoryInfo(args[0]);
                    DirectoryInfo diTarget = new DirectoryInfo(args[1]);

                    bool move = false;
                    bool creationTime = false;
                    string filter = "jpg";
                    for (int i = 2; i < args.Length; i++)
                    {
                        if (args[i] == "/M")
                            move = true;
                        else if (args[i] == "/C")
                            creationTime = true;
                        else if (args[i].StartsWith("/E:"))
                            filter = args[i].Substring(3);
                    }
                    HashSet<string> extensions = new HashSet<string>(filter.Split('/'));
                    FileInfo[] sources = diSource.GetFiles("*", SearchOption.AllDirectories);
                    if (!diTarget.Exists)
                        Directory.CreateDirectory(diTarget.FullName);
                    string targetDirNormalized = diTarget.FullName.TrimEnd('\\', '/') + "/";
                    foreach(FileInfo fi in sources)
                        if (filter.Contains(fi.Extension.StartsWith(".") ? fi.Extension.Substring(1) : fi.Extension))
                        {
                            string timestamp = (creationTime ? fi.CreationTime : fi.LastWriteTime).ToString("yyyyMMddHHmmssfff");
                            int counter = 1;
                            string fileName = GetFileName(targetDirNormalized, timestamp, fi.Extension, counter);
                            while (File.Exists(fileName))
                                fileName = GetFileName(targetDirNormalized, timestamp, fi.Extension, ++counter);
                            if (move)
                                fi.MoveTo(fileName);
                            else
                                fi.CopyTo(fileName, false);
                        }
                }
                else
                {
                    OutputUsage();
                }

            }
            catch (Exception ex)
            {
                ReportError(ex);
            }
        }

        private static string GetFileName(string targetDirNormalized, string timestamp, string extension, int counter)
        {
            if (counter < 2)
                return targetDirNormalized + timestamp + extension;
            return targetDirNormalized + timestamp + " " + counter + extension;
        }

        private static void ReportError(Exception ex)
        {
            Console.ForegroundColor = ConsoleColor.Red;
            Console.WriteLine(ex.ToString());
            Console.ResetColor();
        }

        private static void OutputUsage()
        {
            FileInfo fi = new FileInfo(Environment.GetCommandLineArgs()[0]);
            Console.WriteLine();
            Console.WriteLine("Copies files from the source directory and child directories, ");
            Console.WriteLine("consolidating them in the target directory and renaming the ");
            Console.WriteLine("files to the format yyyyMMddHHmmssfff + .extension where the ");
            Console.WriteLine("timestamp is the last modified date's year, month, day, hour, ");
            Console.WriteLine("minute, second, millisecond.");
            Console.WriteLine();
            Console.WriteLine("\tNote: Files will not be overwritten.  If a file ");
            Console.WriteLine("\talready exists, the new file will have a space and an ");
            Console.WriteLine("\tidentifying number will be appended to the timestamp ");
            Console.WriteLine("\tin the file name (e.g. 20140408010101000.jpg and ");
            Console.WriteLine("\t20140408010101000 2.jpg and 20140408010101000 3.jpg)");
            Console.WriteLine();
            Console.WriteLine("Usage: " + fi.Name.Substring(0, fi.Name.Length - fi.Extension.Length) + " source target [/C] [/M] [/E:Extension1[/Extension2][/Extension3]...]");
            Console.WriteLine();
            Console.WriteLine("\t/C\tNames the files based on creation time instead of modified time.");
            Console.WriteLine("\t/M\tMoves the files instead of only copying them.");
            Console.WriteLine("\t/E:\tSpecify the extension(s) of the files to move or copy.");
            Console.WriteLine("\t\tIf unspecified, only jpg files will be affected.");
            Console.WriteLine();
            Console.WriteLine("\t\tExample: /E:jpg/jpeg/bmp/png/gif/webp/raw");
        }
    }
}
 
Last edited:
  • Like
Reactions: framednlv
BP Thanks,
I'll give it a go later tonight.

How do you set the source directory?
How do you set the target directory?
 
Last edited by a moderator:
Just like any command line application, look at the usage line. Source dir is the first argument. Target dir is the second argument. Then you can add additional arguments if you want to change the behavior.

Code:
Usage: ImageOrganizer source target [/C] [/M] [/E:Extension1[/Extension2][/Extension3]...]

        /C      Names the files based on creation time instead of modified time.
        /M      Moves the files instead of only copying them.
        /E:     Specify the extension(s) of the files to move or copy.
                If unspecified, only jpg files will be affected.

                Example: /E:jpg/jpeg/bmp/png/gif/webp/raw

Here are some examples:

Code:
ImageOrganizer "C:\Unorganized Images" OrganizedImages

This uses an absolute path for the source, and I quoted it because it contains a space. The folder named Unorganized Images in the root of drive C is the source. The target directory is a relative path pointing at a folder named OrganizedImages in the current working directory.



Code:
ImageOrganizer C:\Unorganized "C:\Image Output\OrganizedImages"

Both paths are absolute paths in this case.

Code:
ImageOrganizer input output

Both paths are relative paths.

Code:
ImageOrganizer input output /C

Files are named based on the Creation Date instead of the last modified date.

Code:
ImageOrganizer input output /M

Files are moved instead of copied.

Code:
ImageOrganizer input output /E:png/gif/jpg

png, gif, and jpg files are copied. (if you don't include this argument, then only jpg files are copied)

Code:
ImageOrganizer input output /C /M /E:png/gif/jpg

png, gif, and jpg files are moved and named based on creation date
 
  • Like
Reactions: framednlv
That works great!!!
I'll set it up at home and run it every hour (using the move switch).

Thanks.
Chris
 
It worked fine at work but not at home. Turns out I can't have the ImageOrganizer.exe in the same folder as the sorce directory.
 
I keep getting an error:

Code:
C:\record>ImageOrganizer C:\record\TGC2GW26300052 C:\record\dahua-6mm /C /M /E:jpg
System.ArgumentOutOfRangeException: startIndex cannot be larger than length of
tring.
Parameter name: startIndex
   at System.String.InternalSubStringWithChecks(Int32 startIndex, Int32 length,
Boolean fAlwaysCopy)
   at ImageOrganizer.Program.Main(String[] args)
Any Idea?
 
Hah. You definitely found a bug. I will investigate tomorrow and also check out the 'same folder as the source directory' problem. Can you give more details on that?
 
The camera makes a file called DVRWorkDirectory (no extension) in the source folder. Once this file is deleted it seems to work.
My bat file:
Code:
SET date=%date:~10,4%-%date:~4,2%-%date:~7,2%
md dahua-6mm\%date%
del TGC2GW26300052\DVRWorkDirectory
c:\ImageOrganizer.exe C:\record\TGC2GW26300052 C:\record\dahua-6mm\%date% /C /M /E:jpg

I have the task scheduler running every hour. Seems like a lot of messing around to fix the excessive folder structure.
 
The updated version doen't error out but it does copy the extentionless file to the target directory. Any way to filter that out?

.... And thanks for all the work on this. Sure make viewing the days events fast.
 
I changed to power shell. This is what I ended up with:
Code:
function SortPictures
{
Set-Location \\NAS\Record
Set-Location \\Router\hdd1
#rename files
$files = get-childitem -path $folder -recurse -Include "*.jpeg", "*.jpg" | where { -not $_.PSIsContainer }
[datetime]$dirDate = New-Object DateTime
$i=1000
foreach ($file In $files) {
$i = $i + 1

    $strDate = $file.Name.substring(0,8)

    if (-Not [DateTime]::TryParseExact($strDate, "yyyy-MM-dd",
        [System.Globalization.CultureInfo]::InvariantCulture,
        [System.Globalization.DateTimeStyles]::None, [ref]$dirDate)) {
        $newName = $file.lastwritetime.tostring("yyyy-MM-dd HHmmss") +$i + ".jpg"
        echo $newName
        echo Item -path $file.Fullname -newname $folder + "\"+ $newName
        Rename-Item  -literalpath $file.Fullname -newname  $newName
        #Rename-Item -path $file.Fullname -newname $newName
    } 
}
#move files
get-childItem $folder -recurse | where {$_.length -eq 0} | remove-Item
$files = Get-ChildItem $folder  -Recurse | where {!$_.PsIsContainer}
$files
foreach ($file in $files)
{
$NFolder=$file.LastWriteTime.ToString("yyyy-MM-dd")
$file.Name
$NFolder
$Directory = $targetPath + "\" + $NFolder
$Directory2 = $targetPath2 #+ "\" + $NFolder

#added to echo folder

write-host -fore $nColor $folder
if (!(Test-Path $Directory))
{
New-Item $directory -type directory
}
if (!(Test-Path $Directory2))
{
New-Item $directory2 -type directory
}
$file | Copy-Item -Destination $Directory2
$file | Move-Item -Destination $Directory
}
#empty temp folder
Get-ChildItem $folder -recurse | Where {$_.PSIsContainer -and @(Get-ChildItem -Lit $_.Fullname -r | Where {!$_.PSIsContainer}).Length -eq 0}  | Remove-Item -recurse -WhatIf
Get-ChildItem $folder -recurse | Where {$_.PSIsContainer -and @(Get-ChildItem -Lit $_.Fullname -r | Where {!$_.PSIsContainer}).Length -eq 0}  | Remove-Item -recurse #-WhatIf
}


#add camera snapshot location in the folder
#add target path to copy to
#add target path2 to move files

$nColor = "green"
$folder = "\\router\hdd1\Camera_01"
$targetPath = "\\NAS\Record\Camera_01"
$targetpath2 = "C:\Users\dad\Documents\sorting\camera\Camera_01\"
SortPictures

$nColor = "Magenta"
$folder = "\\router\hdd1\Camera_02"
$targetPath = "\\NAS\Record\Camera_02"
$targetpath2 = "C:\Users\dad\Documents\sorting\camera\Camera_02\"
SortPictures

$nColor = "Cyan"
$folder = "\\router\hdd1\Camera_03"
$targetPath = "\\NAS\Record\Camera_03"
$targetpath2 = "C:\Users\dad\Documents\sorting\camera\Camera_03\"
SortPictures

$nColor = "blue"
$folder = "\\router\hdd1\Camera_04"
$targetPath = "\\NAS\Record\Camera_04"
$targetpath2 = "C:\Users\dad\Documents\sorting\camera\Camera_04\"
SortPictures

$nColor = "red"
$folder = "\\router\hdd1\Camera_05"
$targetPath = "\\NAS\Record\Camera_05"
$targetpath2 = "C:\Users\dad\Documents\sorting\camera\Camera_05\"
SortPictures

$nColor = "red"
$folder = "\\router\hdd1\Camera_06"
$targetPath = "\\NAS\Record\Camera_06"
$targetpath2 = "C:\Users\dad\Documents\sorting\camera\Camera_06\"
SortPictures

$nColor = "Yellow"
$folder = "\\router\hdd1\Camera_07"
$targetPath = "\\NAS\Record\Camera_07"
$targetpath2 = "C:\Users\dad\Documents\sorting\camera\Camera_07\"
SortPictures

$nColor = "Green"
$folder = "\\router\hdd1\Camera_08"
$targetPath = "\\NAS\Record\Camera_08"
$targetpath2 = "C:\Users\dad\Documents\sorting\camera\Camera_08\"
SortPictures

explorer.exe "C:\Users\dad\Documents\sorting\camera"


Since I don't do programming, it took me a while to put this together from the internet.
I set this up to rename and copy the files to my laptop then move the files to my NAS.
To use it set the $folder to the location of the pictures, set $targetPath to move the files and set $targetpath2 to copy the files. You will also need to setup PowerShell to run scripts, search 'How to enable execution of PowerShell scripts'.

Feel free to comment on the program as I am not the good at hacking together scripts.
 
Python is a pretty fun language to use and could do this pretty easily. A bit of a learning curve, but tons of examples out there to get started and something like this wouldn't require much more than learning a basic python app along with how to process files/folders.