DZone
Thanks for visiting DZone today,
Edit Profile
  • Manage Email Subscriptions
  • How to Post to DZone
  • Article Submission Guidelines
Sign Out View Profile
  • Post an Article
  • Manage My Drafts
Over 2 million developers have joined DZone.
Log In / Join
Refcards Trend Reports Events Over 2 million developers have joined DZone. Join Today! Thanks for visiting DZone today,
Edit Profile Manage Email Subscriptions Moderation Admin Console How to Post to DZone Article Submission Guidelines
View Profile
Sign Out
Refcards
Trend Reports
Events
Zones
Culture and Methodologies Agile Career Development Methodologies Team Management
Data Engineering AI/ML Big Data Data Databases IoT
Software Design and Architecture Cloud Architecture Containers Integration Microservices Performance Security
Coding Frameworks Java JavaScript Languages Tools
Testing, Deployment, and Maintenance Deployment DevOps and CI/CD Maintenance Monitoring and Observability Testing, Tools, and Frameworks
Partner Zones AWS Cloud
by AWS Developer Relations
Culture and Methodologies
Agile Career Development Methodologies Team Management
Data Engineering
AI/ML Big Data Data Databases IoT
Software Design and Architecture
Cloud Architecture Containers Integration Microservices Performance Security
Coding
Frameworks Java JavaScript Languages Tools
Testing, Deployment, and Maintenance
Deployment DevOps and CI/CD Maintenance Monitoring and Observability Testing, Tools, and Frameworks
Partner Zones
AWS Cloud
by AWS Developer Relations

Automatic music categorization with .NET

Denzel D. user avatar by
Denzel D.
·
Jul. 01, 10 · Interview
Like (0)
Save
Tweet
Share
4.81K Views

Join the DZone community and get the full member experience.

Join For Free

If you have used a music player on your computer, you probably know that there is a future called “folder watch” – you can set a folder for the player to watch, and once new files are dropped into that folder, those get automatically sorted in various folders based on the artist and albums, assigned to that artist.

In this article, I am going to show how to implement similar functionality with shell interactions and FileSystemWatcher.

First of all, I am working with a sample console application (it really doesn’t matter what application type this is at the moment).

Add a reference to shell32.dll to your project. It can be found in the System32 subfolder in your Windows folder. I will be using this DLL to get the MP3 information. I am only using MP3 files in this article. The ID3 data is read with the help of file columns that can be read via the Folder class in Shell32.

First of all, let’s create an instance of FileSystemWatcher that will be watching the folder for changes. It works continuously (unless you explicitly disable it) while the application is running. Once the application is closed, it is no longer active, so if you want to have a somewhat permanent folder watch, you might want consider developing a service instead.

Here is what I used to create my instance of FileSystemWatcher:

FileSystemWatcher watcher = new FileSystemWatcher();

watcher.NotifyFilter = NotifyFilters.FileName | NotifyFilters.LastWrite;
watcher.Filter = "*.mp3";
watcher.Created += new FileSystemEventHandler(watcher_Created);
watcher.Path = @"D:\Temporary";
watcher.EnableRaisingEvents = true;

The NotifyFilter sets the type of changes to watch for. In our case it will track down new files that are dropped in the folder (existing files will remain). The Filter property sets the file format to watch, so at the moment it only applies to MP3 files. Created points to a new event handler that will be triggered once the watcher is notified of a change that needs to be handled. Path sets the path that needs to be watched and EnableRaisingEvents allows the watcher to trigger its events when necessary. Of course, you can set a different folder to watch than the one I indicated here.

The folder is being watched now, if you launch the application. But this is not the only purpose of the application. We need to move new files to folders, categorizing those by artist name and album name. To do this, I created a separate method called OrganizeFiles:

void OrganizeFiles(string watchPath, string path, string name)
{
string artist;
string album;

try
{
Shell shell = new Shell();
Folder folder = shell.NameSpace(watchPath);
FolderItem folderItem = folder.ParseName(name);
artist = folder.GetDetailsOf(folderItem, 13);
album = folder.GetDetailsOf(folderItem, 14);

if ((!string.IsNullOrWhiteSpace(album)) && (!string.IsNullOrWhiteSpace(artist)))
{
string perspectiveDir = watchPath + @"\" + artist + @"\" + album;
if (Directory.Exists(watchPath + @"\" + artist))
{
if (Directory.Exists(perspectiveDir))
{
File.Move(path, perspectiveDir + "\\" + name);
}
else
{
Directory.CreateDirectory(perspectiveDir);
File.Move(path, perspectiveDir + "\\" + name);
}
}
else
{
Directory.CreateDirectory(perspectiveDir);
File.Move(path, perspectiveDir + "\\" + name);
}
}
}
catch (Exception ex)
{
Debug.Print(ex.Message);
}

}

First of all, make sure you have Shell32 referenced in your project, as well as the System.IO namespace, before using this method.

The instance of Folder sets the main folder where files that contain necessary data are placed. In this case, it will be the same folder used by the FileSystemWatcher instance, therefore I am passing it via watchPath. The instance of FolderItem handles the file passed to it, so I am passing it the MP3 file name via name.

The interesting part comes when I am trying to use Folder.GetDetailsOf(FolderItem,ColumnID). For MP3 files, not only the artist and album data is exposed. In case you want to implement a different type of categorization (for example, based on rating), take a look at this graphic showing the column IDs and the data that is stored in that specific column for the specified file. In this case it applies to MP3 files, so it might be different for other file types.


 
Following this structure, I can easily select the needed columns to obtain various information about a track. If you look at the method above, you can see that I am only selecting the artist and album, since this is what my categorization process relies on.

After I tried to obtain the artist and album name, I am checking whether those are not empty. I do not want to categorize files without proper ID3 data, so I am only putting the file in a different category folder if it has both the artist and the album set.

If the folder already exists (artist/album), the file is simply moved. If not, the proper folders are created and then the file is moved.

But at this moment, the application doesn’t do much. We need to actually create the event handler that will be triggered once a proper file is dropped. To do this, we already declared that there is watcher_Created that handles the process. It looks like this:

void watcher_Created(object sender, FileSystemEventArgs e)
{
var fs = (FileSystemWatcher)sender;

OrganizeFiles(fs.Path,e.FullPath, e.Name);
}

Here, I am getting the sender and I am using it as a FileSystemWatcher -  to read the path that is passed to the OrganizeFiles method as the watch patch. Then, I am getting the full path for the file dropped in the folder as well as its name, also passed to the OrganizeFiles method.

If you run the application and create a new MP3 file inside the folder that you set to be watched over, you will see that the file will be moved to an artist/album folder, if the file has proper ID3 information.

application

Opinions expressed by DZone contributors are their own.

Popular on DZone

  • How To Use Linux Containers
  • Choosing the Right Framework for Your Project
  • DevOps for Developers — Introduction and Version Control
  • Software Maintenance Models

Comments

Partner Resources

X

ABOUT US

  • About DZone
  • Send feedback
  • Careers
  • Sitemap

ADVERTISE

  • Advertise with DZone

CONTRIBUTE ON DZONE

  • Article Submission Guidelines
  • Become a Contributor
  • Visit the Writers' Zone

LEGAL

  • Terms of Service
  • Privacy Policy

CONTACT US

  • 600 Park Offices Drive
  • Suite 300
  • Durham, NC 27709
  • support@dzone.com
  • +1 (919) 678-0300

Let's be friends: