A Collection of Recent Projects: March 2022 Edition

I had been thinking about writing posts on a few different projects I’ve been working on, but none of them had any sort of substance. So instead, here’s something of a showcase, with a few projects I’ve made in the last month or two.

Scatterbrain

The first project is a simple to-do application, made just for me. I’m making it with Qt, using C++, which I haven’t touched in any serious capacity since college.

I made Scatterbrain to solve a single problem: When I get bored of a project, I close my IDE and start procrastinating, and that leads to me shaming myself not getting things done when I have so many things in-flight. Instead, I can click a button in Scatterbrain and it’ll load up a random project of mine.

It’s not styled very well (I mean, it’s a default Windows application, but that doesn’t look the greatest), and my C++ is rusty, but it gets the job done! I’ve been using it for about a month now, and it still requires a bit of conscious effort to not procrastinate, but I reduced the friction to get to the next project and that has helped a lot.

I'm not feeling like much of a Qt...

There are a few more things I’m planning on adding, to bring it more in line with what you’d expect from a to-do app. I want better task filters, for when projects get a bit too big. I want to implement a better data solution (I’m just using a single JSON file per project in the user’s appdata, which don’t get me wrong, it does what it needs to do just fine). I’m sure more things will crop up as this is my current pet project.

You can check out the source here.

HouseBot

Yet another Discord bot! I haven’t made one since ScrubBot, and this time, I’m making one for my roommates and I. This one is still very much a work-in-progress, but I’m giving it its own section because it’s going places (hopefully).

Initially, we were just looking for a bot to do polls in our server, but we weren’t too fond of the existing options. We were choosing between a bot that only did polls, but without the full feature set we were looking for, or a bot that did polls and way too many other things. So, as you do in a house full of engineers, we decided to do it ourselves.

To be hosted on our home server, the bot currently only does the polls we originally wanted, but as we got brainstorming, we decided on a few other features:

  1. Controlling our HUE lights
  2. Controlling the Nest thermostat
  3. Pinging our roommate Ryan whenever the bot does anything

Are any of these things necessary? Of course not, we all have the apps to control these things, and I can spam Ryan whenever I want! But it’s kind of cool to be able to do everything through Discord, something we already spend so much time in. And with local hosting, we don’t really have to worry about exposing our smart home to the world (though if anyone hopped into our house server, they’d be able to control our house, how fun).

Random Utilities

These next few aren’t really what I would consider full-fledged projects, but rather small scripts to accomplish some boring tasks.

File Lifter

Simple one to start off with. I had a bunch of archives that were organized terribly, and I just wanted to get all the photos out of them. After a few rounds of spamming Ctrl-X, Ctrl-V, I decided to just write a script. This one was simple enough to just throw it all here:

def get_file_list(top_path, extensions):
    paths = []
    for root, dirs, files in os.walk(top_path):
        for file in files:
            for extension in extensions:
                if file.endswith(extension):
                    paths.append(os.path.join(root, file))
                    break
    return paths

def lift_files(directory, extensions_string):
    os.makedirs(os.path.join(directory, "_LIFTED"))

    extensions = extensions_string.split(',')
    file_list = get_file_list(directory, extensions)
    file_count = len(file_list)
    print(f"Lifting {file_count} files...")
    for file in file_list:
        new_file_name = os.path.join(directory, "_LIFTED", os.path.basename(file))
        shutil.copy2(file, new_file_name)
        print(f"Moved [{file}] to [{new_file_name}]")
    print(f"Lifted {file_count} files.")

All you do is supply a comma-delimited string of extensions and a top-level directory, and it will lift all the files with those extensions to a new directory in the top-level.

Text File Comparer

This one came from a need to find what games were unique between three massive charity bundles Itch.io has run in the past year. Part of this was an older Selenium program I wrote that will go through the bundle and claim the 1000+ games to your account. I modified that to just spit out a text file with the titles of the games in the bundles, and wrote the following script to compare them:

def get_files_from_args():
    file_paths = sys.argv[1:]
    valid_paths = []
    for file_path in file_paths:
        if os.path.exists(file_path):
            valid_paths.append(file_path)
    return valid_paths

def run_comparer(file_paths):
    file_sets = []
    for file_path in file_paths:
        with open(file_path, 'r') as f:
            file_lines = f.readlines()
        file_sets.append(set(file_lines))

    op_choice = input("Choose operation:\n1. All unique lines\n2. Lines unique to each file\n3. Lines in all files")

    if op_choice == "1":
        combined_set = get_unique_lines(file_sets)
        print(f"{len(combined_set)} lines:")
        print("".join(combined_set))
    elif op_choice == "2":
        individual_sets = get_individual_unique_lines(file_sets)
        for _set in individual_sets:
            print(f"{len(_set)} lines:")
            print("".join(_set))
    elif op_choice == "3":
        combined_set = get_lines_in_all_files(file_sets)
        print(f"{len(combined_set)} lines:")
        print("".join(combined_set))
    else:
        return

def get_unique_lines(sets):
    return set.union(*sets)

def get_individual_unique_lines(sets):
    individual_sets = []

    for i in range(len(sets)):
        individual_set = sets[0] - set.union(*sets[1:])
        individual_sets.append(individual_set)

    return individual_sets

def get_lines_in_all_files(sets):
    return set.intersection(*sets)

This used to be a bit bigger, but then I learned the magic of all the set operations in Python, which haven’t come up often for me!

Weekly Game Jam Theme Scraper

Another Selenium project, this time to procure a large list of game jam themes from the Weekly Game Jam series on Itch.io. I created this one to get more data for an idea generator when I was trying to do some speedy brainstorming.

That ultimately resulted in a spreadsheet that combined

  1. My friend’s favorite games (and their favorite mechanics from those games)
  2. The complete list of mechanics from BoardGameGeek
  3. The scraped game jam themes
  4. A sorta complete list of video game genres

From that, I can roll on the sheet and get…

I'm sure there's something there

Until Next Time

It’s nice to write a little on these projects that just get made and discarded, so I’ll try to make a habit of it. Once a quarter maybe? We’ll have to see.