Link to home
Start Free TrialLog in
Avatar of trevor1940
trevor1940

asked on

C#: Renaming jpg's to match a corrisponding video file

Hi

I'm trying to search a given directory for video and jpg files matching / renaming the jpg to the video
If a video file has a jpg with the same name I can skip it
else I want the user to choose from the list within the directory by typing the associated number or  a completely  new option / x (for no jpg)


in my test folder I have
File01.mp4
File02.mkv
File01.jpg
pic.jpg
SubFold
File01.jpg
File03.mp4
File03.mp4_snapshot_18.48_2019.06.03_19.50.59.jpg
File04.mp4
File04.jpg
File05.mp4
File garbish5.jpg

In the code bellow

First I'm not listing the top level directory only SubFold
Second how do I alow the users chose with the jpg file so I can rename it but filter out the jpg's  that already have a video
(Top folder don't show File01.jpg because of File01.mp4 SubFold Show File01.jpg, File03.mp4_snapshot_18.48_2019.06.03_19.50.59.jpg & File garbish5.jpg )
once the jpg has been rename this is no longer an option)

Some jpg files could be Auto renamed like "File03.mp4_snapshot_18.48_2019.06.03_19.50.59.jpg" but for now I just need to the manual choice


 
using System.IO;

namespace Kodi
{
    class Program
    {
        static void Main(string[] args)
        {
            string BaseFold = "";
            string Ans; 
            if(args == null)
            {
                Console.WriteLine("Drag a Folder to search");
                Ans = Console.ReadLine();
                BaseFold = Ans;
            }
            else
            {
                BaseFold = args[0];
            }
            Console.WriteLine("You chose {0}", BaseFold);

                if (BaseFold.EndsWith(@""""))
                {
                    BaseFold = BaseFold.Trim(new char[] { '"' });
                    Console.WriteLine("trimed " + BaseFold);
                }
                    if (Directory.Exists(BaseFold))
                    {
                        // Get dirs recursively 
                        string[] folders = Directory.GetDirectories(BaseFold, "*", SearchOption.AllDirectories);


                        foreach (string folder in folders)
                        {
                            FileInfo DI = new FileInfo(folder);
                            String dirName = DI.Directory.Name;
                        Console.WriteLine(dirName);
                            if (dirName == "used" || dirName == "pics"   )
                            {
                                continue;
                            }
                            var Files = Directory.EnumerateFiles(folder, "*", SearchOption.TopDirectoryOnly).Where(s => s.EndsWith(".mp4") || s.EndsWith(".mkv") || s.EndsWith(".wmv")); 
                            foreach (string VidFile in Files)
                            {
                                FileInfo FI = new FileInfo(VidFile);
                                string VidName = FI.Name;
                                var VidDate = FI.LastWriteTime;
                                string jpgExist = folder + "\\" + VidName + ".jpg";
                                if (File.Exists(jpgExist))
                                {
                                    continue;
                                }
                                else
                                {
                                   Console.WriteLine("Choose a jpg to go with\n{0} date {1} or x for none\n", VidName, VidDate);
                                   var jpgFiles = Directory.EnumerateFiles(folder, "*", SearchOption.TopDirectoryOnly).Where(s => s.EndsWith(".jpg"));
                                int Count = 0;
                                   foreach(string jpgFile in jpgFiles)
                                    {
                                        FileInfo JI = new FileInfo(jpgFile);
                                        string Jname = JI.Name;
                                        var Jdate = JI.LastWriteTime;
                                        Console.WriteLine("{0} {1} {2}", Count, Jname, Jdate   );

                                    Count++;
                                    } 


                                }
                                 

                            }


                        }
                    }
            Console.ReadLine();
        }
    }
}

Open in new window

ASKER CERTIFIED SOLUTION
Avatar of gr8gonzo
gr8gonzo
Flag of United States of America image

Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
Avatar of trevor1940
trevor1940

ASKER

I'm only seeing the contents of the Subfolder(s)  not the top level folder

Choosing which jpg goes with the video file

 regular expressions could help with some however I need a mechanism where the user can pick from available jpg's in the same folder (Not already linked to a video)   as sometimes the jpg's names have no relation to the associated video

I've written something similar in perl years ago then I pushed the options into an indexed array the user was shown the list and picked the number for whatever was the correct choice

Yes I will create a class once I've overcome this obstacle I intend to create kodi NFO files
Any particular reason you're trying to do this as a console application?  Seems like the user experience would be so much easier with a WinForms app w/ a ListBox to choose the match from...
Wait, are you saying that you -want- the top folder contents listed?

Right now, you have:
string[] folders = Directory.GetDirectories(BaseFold, "*", SearchOption.AllDirectories);

...which returns all the subfolders inside BaseFold, and then you are looping through that "folders" array. So if you want to include "BaseFold" in the list of folders to loop through, then just add it to "folders". Just add this right below your "string[] folders..." line:
Array.Resize(ref  folders, folders.Length+1);
folders[[folders.Length - 1] =  BaseFold;

Open in new window


For the JPG selection, I'd strongly recommend what Mike is saying - the best UI is going to come from a ListBox. Otherwise, if you have a lot of options to select from, it's going to become really cumbersome to use.

Otherwise, if you need to stick with the console, you already have most of the pieces in place - the Console.ReadLine() call will give you input. Just convert jpgFiles to an array so you have numeric indexing, then output the jpgFile options, prompt the user for selection, and process the response.

Step 1: Convert jpgFiles to an array
BEFORE: var jpgFiles = Directory.EnumerateFiles(folder, "*", SearchOption.TopDirectoryOnly).Where(s => s.EndsWith(".jpg"));
AFTER: var jpgFiles = Directory.EnumerateFiles(folder, "*", SearchOption.TopDirectoryOnly).Where(s => s.EndsWith(".jpg")).ToArray();

Step 2: Loop through jpgFiles and output as options:
Console.WriteLine("Choose an option:");
for(int i = 0; i < jpgFiles.Length; i++)
{
    Console.WriteLine(i + 1 + ". " + jpgFiles[i]);
}
Console.WriteLine("Or type 0 to exit.");

Open in new window


Step 3: Parse the input
// Prompt for user selection and keep prompting until we get a valid one
int userSelection = -1;
while(true)
{
    if(int.TryParse(Console.ReadLine(), out userSelection))
    {
        // User input was between 0 (exit) and the last option in the JPG files array
        if ((userSelection >= 0) && (userSelection <= jpgFiles.Length))
        {
            break;
        }
    }
    else
    {
        Console.WriteLine("Invalid option. Please try again.");
    }
}

Open in new window




Step 4: Handle the selection
// Since we used 0 for Exit, subtract 1 so that -1 becomes Exit and userSelection aligns with our 0-based array index
userSelection--;
if(userSelection == -1)
{
    // Code to exit
    return;
}
else
{
    // JPG option
    string selectedJpgFile = jpgFiles[userSelection];

    // Do with it as you will...
}

Open in new window


I haven't actually tried the above code, but it should work in theory.
Thanx gr8gonzo  I assumed
string[] folders = Directory.GetDirectories(BaseFold, "*", SearchOption.AllDirectories);

Meant everything

Today I've been playing with your Dictionary idea which could be the way forward

As for the UI

Within a listview can you have two columns  Videos and JPG's then  drag & drop the JPG 's to sort?

The end result would be per directory a 2 column sorted list with the Video and matching JPG per row
Absolutely.  You could also use a DataGridView instead of a ListView.
As @gr8gonzo answered the opening question he wins
However I like Mikes idea so i'm going to look into it