Snapshot manipulation?

framednlv

Getting the hang of it
Joined
Mar 17, 2014
Messages
254
Reaction score
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:

bp2008

Staff member
Joined
Mar 10, 2014
Messages
12,674
Reaction score
14,020
Location
USA
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.
 

framednlv

Getting the hang of it
Joined
Mar 17, 2014
Messages
254
Reaction score
69
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

bp2008

Staff member
Joined
Mar 10, 2014
Messages
12,674
Reaction score
14,020
Location
USA
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:

framednlv

Getting the hang of it
Joined
Mar 17, 2014
Messages
254
Reaction score
69
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:

bp2008

Staff member
Joined
Mar 10, 2014
Messages
12,674
Reaction score
14,020
Location
USA
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
 

framednlv

Getting the hang of it
Joined
Mar 17, 2014
Messages
254
Reaction score
69
That works great!!!
I'll set it up at home and run it every hour (using the move switch).

Thanks.
Chris
 

framednlv

Getting the hang of it
Joined
Mar 17, 2014
Messages
254
Reaction score
69
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.
 

framednlv

Getting the hang of it
Joined
Mar 17, 2014
Messages
254
Reaction score
69
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?
 

bp2008

Staff member
Joined
Mar 10, 2014
Messages
12,674
Reaction score
14,020
Location
USA
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?
 

framednlv

Getting the hang of it
Joined
Mar 17, 2014
Messages
254
Reaction score
69
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.
 

bp2008

Staff member
Joined
Mar 10, 2014
Messages
12,674
Reaction score
14,020
Location
USA
Here is an updated version that should have that bug fixed. I expect you had a file with no extension in that source directory.

Update: Now on github: bp2008/ImageOrganizer
 
Last edited:

framednlv

Getting the hang of it
Joined
Mar 17, 2014
Messages
254
Reaction score
69
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.
 

framednlv

Getting the hang of it
Joined
Mar 17, 2014
Messages
254
Reaction score
69
Thanks.
Works great.....
Now I need to tweak the motion detection for my cameras.
 

framednlv

Getting the hang of it
Joined
Mar 17, 2014
Messages
254
Reaction score
69
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.
 

gregbert

Getting the hang of it
Joined
Jan 9, 2017
Messages
66
Reaction score
33
Location
Lewisville, TX
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.
 
Top