Updated Firefly III Shortcuts for iOS 13

Back in March I shared a few iOS shortcuts to add transactions to a Firefly III when on the go. Both Shortcuts and Firefly III’s API have changed in the interim, and I’ve finally got around to updating my shortcuts to reflect those changes.

The bulk of the changes for iOS 13 were just structural, and iOS 13 allowed for some merging of steps. Firefly III 4.8 also changed the API to post transactions. Otherwise not much else has been updated.


List Accounts:

www.icloud.com/shortcuts/c5c8b71bc1594737922f731395464989

Add Transaction:

www.icloud.com/shortcuts/11b2f6eb721d42c3b5b8df2bbecb3455


You may also want to check out Sid Verma’s versions that also let you select a category. I didn’t want to add that ability (and still don’t) because I want the least steps possible, want to avoid the added complexity in Shortcuts, and because it fit well into my process.

Quick Script to Migrate from SimpleNotes

Moving hundreds or thousands of notes from SimpleNotes (to Apple Notes in my case)? This script aught to help clean up a few things for a better structure after importing.

  • Converts tags in *.txt files to #tag format for easier searching. Preserves original modified timestamp.
  • Updates the modified timestamps to a UTC offset (if specified)
  • Moves each note file into a subfolder based on its first tag (if specified)

This will only modify txt files, and should be run against an extracted export of notes from SimpleNote, so it should be fairly safe. But keep the archive and/or backups just in case. Use as follows:

chmod +x convert-tags.php
./convert-tags.php --path ./notes --timezone "-0500" --usefolders

Then import the notes folder through Notes.app.


#!/usr/bin/env php
<?
/**
 * This script helps migrate from SimpleNotes to Apple Notes 
 * (and potentially others) in a few ways:
 * 
 * 1) Converts tags in exported SimpleNotes *.txt files
 * to #tag format for easier searching. Preserves original modified timestamp.
 * 2) Updates the modified timestamps to a UTC offset (if specified)
 * 3) Moves each note file into a subfolder based on its first tag (if specified)
 * 
 * Arguments: (in this order)
 * --path - Location of the exported txt files
 * --timezone - an offset value (eg: -0500) from UTC to correct timestamps
 * --usefolders - moves notes into a subfolder based on their first tag
 */

$tags_pattern = '/Tags:\n\s\s(.+)$/';
$updated_files = 0;
$updated_timestamps = 0;
$moved_files = 0;
$errors = 0;
$skipped_files = 0;

$options = getopt(null, ['path:', 'timezone:', 'usefolders:']);

if (!isset($options['path']) || is_dir($options['path']) !== true) {
    throw new Exception('--path argument is missing or invalid.');
}

$base = trim($options['path'], '/') . '/';

if ( isset($options['timezone']) ) {
    if ( preg_match('/[-+]\d\d:?\d\d/', $options['timezone']) === 1 ) {
        // Calculate interval in seconds for the supplied timezone offset 
        $dtz_utc = new DateTimeZone('UTC');
        $dtz_offset = new DateTimeZone($options['timezone']);
        $dt_utc = new DateTime('now', $dtz_utc);
        $utc_offset_seconds = $dtz_offset->getOffset($dt_utc);

        $di_offset = DateInterval::createFromDateString( abs($utc_offset_seconds) . ' seconds');

        if ($utc_offset_seconds < 0) {
            $di_offset->invert = 1;
        }

        echo "Modified timestamps will be adjusted by {$utc_offset_seconds} seconds.\n";
    } else {
        throw new Exception('Timezone format should be -0500.');
    }
} else {
    echo "Not adjusting timezone of modified timestamps.\n";
    $di_offset = null;
}

$use_folders = in_array('--usefolders', $argv);

if ($use_folders) {
    echo "Moving notes into subfolders\n";
} else {
    echo "Leaving notes in $base\n";
}


if ($handle = opendir($base)) {
    echo "Updating *.txt in $base\n";
    echo "---\n";

    while (false !== ($entry = readdir($handle))):

        // Skip non-txt files
        if (preg_match('/^.*\.txt$/', $entry) !== 1) {
            echo "Skipping '$entry'\n";
            $skipped_files++;
            continue;
        }

        if ($contents = file_get_contents($base . $entry) ):
            $tags = [];

            // Find the tags string, replace with new format, and stash tags for later use
            $new_contents = preg_replace_callback($tags_pattern, function ($matches) use (&$tags) {
                $tags = explode(', ', $matches[1]);
                return '#' . implode(' #', $tags);
            }, $contents);

            $original_mod_time = filemtime($base.$entry);

            if ($contents !== $new_contents) {
                if (file_put_contents($base . $entry, $new_contents) !== false) {
                    echo "Updated '$entry'\n";
                    $updated_files++;
                }
            }
            
            // Resetting modified timestamp back to original 
            $date = new DateTime( '@'.$original_mod_time );
            
            // Correct modified timestamp's timezone
            if ($di_offset) {
                $date->add($di_offset);
            }
            
            // Set the timestamp
            if ( touch($base.$entry, $date->getTimestamp()) ) {
                $updated_timestamps++;
            }

            // If specified, move the note into a folder based on the first tag
            if ($use_folders && count($tags)) {
                $folder = $base . $tags[0] . '/';

                if (!is_dir($folder)) {
                    mkdir ($folder);
                }

                if ( rename($base.$entry, $folder.$entry) ) {
                    echo "Moved '$entry' to '" . $folder . $entry . "'\n";
                    $moved_files++;
                } else {
                    echo "*** Could not move '$entry' to '" . $folder . $entry . "'\n";
                    $errors++;
                }
            }
        endif;
    endwhile;

    closedir($handle);
}

echo "---\n";
echo "Skipped $skipped_files files/folders.\n";
echo "Updated $updated_files files.\n";
if ($use_folders) {
    echo "Moved $moved_files files.\n";
}
if ($di_offset) {
    echo "Modified and reset timestamps on $updated_timestamps files.\n";
} else {
    echo "Reset timestamps on $updated_timestamps files.\n";
}
if ($errors) {
    echo "** Encountered $errors errors.\n";
}