Adam O'Grady

Music Library System

This entry feels like a bit of a copout, however I feel pretty good with what I’ve done so far. For years I’ve used iTunes to manage my library and it would always be on my main PC, meaning anyone who wanted to play music from our massive library of tracks would have to play it on my PC and hope I’m not doing anything that also has sound. We considered putting the music on the file server (rather than just the backup) and allowing multiple computers to connect to it, however any added music would not automatically appear on other clients, breaking the integrity of the library.

So my current plan is to develop a singular, central client (maybe the RaspberryPi or Parallella) that periodically (and/or on demand) searches the library for new, moved or edited files and then develops a database of them all. Another component (perhaps on RPi or a new one) will read from the database and provide a web interface (and hopefully API for mobile apps) that all computers on the network can connect to and choose a song to play, while being able to sort by ID3 tags including artist, album, genre, etc.

After a decently early wake up today I got some work done on the initial part of this project. I created a little C++ executable that takes in a file name with it’s working path then computes it’s MD5 hash and returns it as a hex string. I tested it against an online service to great success. I also built a small Erlang script that you can pass a file/folder and it’s path and it will calculate the MD5 hashes of each file/folder (recursively) contained within.

EDIT: Updates to this project will likely appear in my GitLab.

MD5LibraryCheck

main.cpp

#include <iostream>
#include <iomanip>
#include <sstream>
#include <string>
#include <openssl/md5.h>

using namespace std;

int main(int argc, const char * argv[])
{
    FILE *file = fopen(argv[1], "rb");
    unsigned char hash[MD5_DIGEST_LENGTH];
    MD5_CTX md5;
    MD5_Init(&md5);
    const int bufSize = MD5_DIGEST_LENGTH;
    void *buffer = malloc(bufSize);
    size_t bytesRead = 0;
    while ((bytesRead = fread(buffer, 1, bufSize, file))) {
        MD5_Update(&md5, buffer, bytesRead);
    }
    MD5_Final(hash, &md5);
    fclose(file);

    stringstream ss;
    for (int i = 0; i < MD5_DIGEST_LENGTH; i++) {
        ss << hex << setw(2) << setfill('0') << (int)hash[i];
    }
    std::cout << ss.str();

    free(buffer);
    return 0;
}

Filesystem Scanner

scanner.erl*

-module(scanner).
-include_lib("kernel/include/file.hrl").
-compile(export_all).

discover(Entry, Cwd) ->
    file:set_cwd(Cwd),
    {ok, EntryRead} = file:read_file_info(Cwd ++ "/" ++ Entry),
    case EntryRead#file_info.type of
        directory ->
            exploredir(Entry, Cwd);
        regular ->
            spawn(?MODULE, checksumfile, [Entry, Cwd])
    end.

exploredir(Directory, Cwd) ->
    {ok, Filenames} = file:list_dir(Cwd ++ "/" ++ Directory),
    [discover(X, Cwd ++ "/" ++ Directory) || X <- Filenames].

checksumfile(Entry, Cwd) ->
    io:format("~p/~p: ~p~n", [Cwd, Entry, os:cmd("md5hash " ++ Cwd ++ "/" ++ Entry)]).

Both of these are incredibly simple so they’re available without copyright, feel free to use them how you want!