Organize Your Downloads Folder with Ruby #2
Tags: webdev, ruby, programming, beginners
Published: 2023-02-07 09:22:10

So, after working with a side-project for about 6 hours today, pulling my hair because CSS makes absolutely no sense to me sometimes, I decided to improve on the `Downloads Organizer` I made in Ruby the other week. 

**_This is part two / version two. You can view the first article here:_** [Organize Your Downloads Folder with Ruby](https://dev.to/smackdh/automating-downloads-cleanup-with-ruby-3006)

---

So what I added was a way of checking the type of the files, and also organizing them into their own subfolders. To achieve this I used `regex` to the check the file-endings of the files.

After getting it to work, I had to refactor.. **A LOT..** But here are the final results, a couple of functions doing bits and pieces I'll walk you through under the codeblock.

---

```ruby
require 'find'
require 'fileutils'

downloads_folder = File.join(Dir.home, 'Downloads')
## Arrays used in the filtering logic.
yearly_folders = ["2019", "2020", "2021", "2022", "2023", "2024", "2025"]

def check_type(file)
  case file
  when /^.*\.(pdf|doc|docx|PAGES|txt)$/i
    'documents'
  when /^.*\.(gif|jpg|jpeg|png|svg|mp4|mov|mp3|mpeg4|heic)$/i
    'media'
  when /^.*\.(dmg|exe|jar)$/i
    'programs'
  when /^.*\.(zip|tar|rar)$/i
    'archives'
  else
    'other'
  end
end

def create_directory(directory, subfolder)
  final_directory = File.join(directory, subfolder)
  Dir.mkdir(final_directory) unless File.directory?(final_directory)
  final_directory
end

def move_file(file, directory)
  final_directory = create_directory(directory, check_type(file))
  FileUtils.mv(file, final_directory) unless file === directory
end

def organize_downloads(downloads_folder, yearly_folders)
  Dir.foreach(downloads_folder) do |file|
    next if file == '.' || file == '..' || yearly_folders.include?(file)

    path = File.join(downloads_folder, file)
    next unless File.exist?(path)

    last_edited = File.mtime(path)
    year = last_edited.strftime('%Y')
    new_directory = create_directory(downloads_folder, year)

    move_file(path, new_directory)
  end
end

organize_downloads(downloads_folder, yearly_folders)

```

So, when the app is started, running the `organize_downloads` method, the same old logic used for getting the files, and year modified as explained in part 1. 

When it starts to differ is when assigning `new_directory` to the value of `create_directory`.

##1 **`create_directory`**
In this method, we give it two attributes: `directory` and `year`, which is set in `organize_downloads`. It then creates a new variable, that eventually just returns a path to the location we want to put the file in.

From there we create a new folder with the new path, `UNLESS` the folder already exist.

And finally, we return the `final_folder` path.


Now, back to `organize_downloads` and what happens in `move_file`

##2 **`move_file`**

Here, we give it two attributes: `path`, which basically is the pointer to the file itself, and `new_directory` which is the return that we got from the `create_directory` in step 1.

In here, we again create a `final_directory`, but this time to also include subfolders.

This one is pretty easy, it re-uses the `create_directory` method again, but to create the subfolder. But instead of having the `downloads_folder` and `year`, we instead give it the updated directory(`directory`) and the return of whatever `check_type` does _(explained in step 3)_.

And after getting these values, we run the same `FileUtils.mv`to just move it to its new location.


##3 **`check_type`**

The last piece of the puzzle to explain, and the easiest. A switch condition that checks if the letters/digits after "." at the end of the filename matches a specific set of filetypes set by me.

How I decided to structure mine was:
- **Media** (images/videos)
- **Programs** (apps, installers)
- **Documents** (PDFs, docs)
- **Archives** (rar-files etc)
- **Other** (The rest)

_I'm sure I've probably missed filetypes etc, but I just wanted to get it to work really._

It then returns a string for whatever match it gets, and then goes on with the logic back in `move_file`.

---

And that's it! Version 2.0 of my Ruby app organizing the downloads folder. Good times.

In the future I would like to look at:
- Add more structure
- Potentially make it even more dynamic and take inputs
- GUI? 👀