David Vedvick

Side Projects

Picture Categorizer

Picture Categorizer is public image gallery software. An instance of Picture Categorizer runs at Catpics!, devoted entirely to those animals we most love, cats! To best serve our cat overlords, Picture Categorizer has gone through several different iterations:

  1. Originally developed in Kotlin + Spring Boot as a fun software engineering project for my master's.
  2. Next, the server back-end was migrated to Ktor to improve resource usage as Spring Boot has pretty heavy resource requirements.
  3. Then the server back-end was migrated to ExpressJS/Typescript to further improve resource usage (this surprised me as well).
  4. Finally, to further reduce resource requirements and improve the portability of the application, the database was migrated to SQLite from MySQL.

Given all of these migrations, there may be some artifacts from previous iterations that don't quite make sense in its current form. If you see them, submit a PR to clean them up!

project blue

An alternative, open source streaming music client for JRiver Media Center.

project blue is a streaming audio client for JRiver Media Center (http://jriver.com/). Stream your favorite music and audio from your JRiver Media Center wherever you are!

Its features include:

  • Reliable streaming from your home server running JRiver Media Center via an intuitive layout.
  • Caching of audio files during playback.
  • Synchronize audio from JRMC server to device.
  • Play local files when present and metadata match.
  • Updates server with playback statistics.
  • Edit and update playlists through Now Playing.
  • Interfaces with Bluetooth remote control clients.
  • Android TV Support
  • Supports Android Auto (beta) NOT supported due to strict Google Play requirements.
  • Interfaces with apps that implement the Scrobble Droid interface (Simple Last.fm Scrobbler is my scrobbler of choice) for scrobbling to Last.fm or Libre.fm

Download on the Google Play Store

Requires JRiver Media Center running on your home server

Sharper Integration

Sharper Integration is an AppImage desktop integration program that aims for simple integration via established Linux desktop conventions.

Its features include:

  • Extracts and integrates the desktop icon and desktop file from the AppImage and integrates them with the desktop.
  • Registers App Images with their associated mime-types.
  • Upon installation of itself, associates itself with the AppImage mime-type.
  • Adds options to undo desktop integration and to update the AppImage from the menu (using AppImageUpdate or appimageupdatetool if present in the same directory as SharperIntegration).

Sharper Integration is primarily written in C#.

Try it out

Download SharperIntegration from here and make it executable. Then execute the AppImage, it should prompt you to install itself.

Firejail Support

Firejail runs AppImages within special namespaces isolated from the rest of the system. This means Sharper Integration will be prevented performing its Desktop Integration functions when run within Firejail without broader permissions granted to Sharper Integration.

Codefolio

Codefolio is a basic portfolio object builder for your projects.

Features

  • Follow simple conventions to produce a standard Portfolio object from a Markdown Readme.
  • Or bring your own conventions, and just use Codefolio to produce standard Portfolio objects.

For example, given this markdown in a README.md file:

# Hi I'm a level one heading

![img](./img.png)

Here's the body!

When passed into Codefolio:

const codefolio = require('codefolio');


const portfolios = await codefolio.promisePortfolios(['README.md']);

Produces a Portfolio object like this:

{
  body: "# Hi I'm a level one heading\n\nHere's the body!",
  image: {
    url: "./img.png",
    alt: "img",
    title: "img"
  },
  examples: []
}

Installation

npm install --save-dev codefolio

Handoff, an A+ like Promise Implementation for Java

Handoff is a simple, A+ like Promises implementation for Java. It allows easy control flow to be written for asynchronous processes in Java:

public Promise<PlaybackFile> promiseFirstFile() {
    return new Promise<>(messenger -> {
        final IPositionedFileQueueProvider queueProvider = positionedFileQueueProviders.get(nowPlaying.isRepeating);
        try {
            final PreparedPlayableFileQueue preparedPlaybackQueue = preparedPlaybackQueueResourceManagement.initializePreparedPlaybackQueue(queueProvider.provideQueue(playlist, playlistPosition));
            startPlayback(preparedPlaybackQueue, filePosition)
                .firstElement() // Easily move from one asynchronous library (RxJava) to Handoff
                .subscribe(
                    playbackFile -> messenger.sendResolution(playbackFile.asPositionedFile()), // Resolve
                    messenger::sendRejection); // Reject
        } catch (Exception e) {
            messenger.sendRejection(e);
        }
    });
}

And the promise can then be chained as expected. The method then is used to continue execution immediately using the promised result:

playlist.promiseFirstFile()
    .then(f -> { // Perform another action immediately with the result - this continues on the same thread the result was returned on
        // perform action
        return f; // return a new type if wanted, return null to represent Void
    });

For instances where another promise is needed, the method eventually should be used, and excuse should be used for catching errors, which will fall through if not caught earlier in the method chain.

playlist.promiseFirstFile()
    .eventually(f -> { // Handoff the result to a method that is expected to produce a new promise
        return new Promise<>(m -> {

        });
    })
    .excuse(e -> { // Do something with an error, errors fall through from the top, like with try/catch
        return e;
    });

QueryDroid

A simple library that helps with serializing Android SQLite queries to and from Java objects:

public Collection<Library> getLibraries(Context context) {
  try (RepositoryAccessHelper repositoryAccessHelper = new RepositoryAccessHelper(context)) {
      return repositoryAccessHelper
          .mapSql("SELECT * FROM library")
          .fetch(Library.class);
  }
}

What problems does it solve?

The standard Android library has for ages had numerous ways to pull back data from its built-in SQLite database. However, none of these ways either a) are easy to use, or b) give developers the power they need to develop performant, flexible applications.

In the C# world, developers have long had the excellent Dapper library, which maps C# types nicely to and from C# objects without getting in the way of how you want to write your queries. QueryDroid started off with Dapper as an inspiration and made querying your data in the built-in SQLite library much more natural and cleaner!