Dynamic Match Patterns

NOTE

It's recommended that you go through the 5 Minute Quick Start first to understand how to install and test your plugins.

Wildcard Matching

What if we want a plugin that accepts an arbitrary argument after some key words?

Let's make a plugin that shows the weather for any city when user says: weather for [city name] (eg. weather for Chiang Mai)

Easy peasy.

Use * in your match string to greedily match any words.













 















/// <reference path="../@types/plugin-interface.d.ts"/>
import { PluginBase } from "../PluginBase";

export module WeatherPlugin {
    export let Plugin = Object.assign({}, PluginBase, {
        niceName: 'Weather',
        match: /.*accuweather\.com/,
        commands: [{
            name: 'Check the Weather',
            description: 'Check the weather for a given city.',
            // say it on any page (not just accuweather domain)
            global: true,
            match: ['weather for *', 'forecast for *'],
            pageFn: async (transcript: string, q: string) => {
                // https://api.accuweather.com/locations/v1/cities/autocomplete?q=chiang%20mai&apikey=d41dfd5e8a1748d0970cba6637647d96&language=en-us&get_param=value
                // ex resp: [{"Version":1,"Key":"317505","Type":"City","Rank":41,"LocalizedName":"Chiang Mai","Country":{"ID":"TH","LocalizedName":"Thailand"},"AdministrativeArea":{"ID":"50","LocalizedName":"Chiang Mai"}}]
                // https://www.accuweather.com/en/th/chiang-mai/317505/weather-forecast/317505
                $.get(`https://api.accuweather.com/locations/v1/cities/autocomplete?q=${q}&apikey=d41dfd5e8a1748d0970cba6637647d96&language=en-us&get_param=value`, (resp) => {
                    let cityId = resp[0].Key;
                    let countryCode = resp[0].Country.ID.toLowerCase();
                    let cityName = resp[0].LocalizedName.replace(' ', '-');
                    window.location.href = `https://www.accuweather.com/en/${countryCode}/${cityName}/${cityId}/weather-forecast/${cityId}`;
                });
            }
        }],
    });
}

Numeral Matching

Ain't nothin' to it.

Use # in your match string to match numerals or ordinals including ones that are spelled-out (ie. four-thousand)

Let's write a plugin that opens x tab for y minutes so that we can limit it's time wasting-ness. This might be useful if we need to check facebook but don't want to get sucked into the feed for too long.













 







/// <reference path="../@types/plugin-interface.d.ts"/>
import { PluginBase } from '../PluginBase';

export module AntiProcrastinationPlugin {
    export let Plugin = Object.assign({}, PluginBase, {
        niceName: 'Anti-procrastination',
        description: 'Helpers for overcoming procrastination.',
        match: /.*/,
        commands: [{
            name: 'Self destructing tab',
            description: 'Open a new tab with x website for y minutes. Useful for limiting the time-sucking power of sites like facebook, reddit, twitter etc.',
            global: true,
            match: 'open * for # minutes',
            pageFn: async (transcript: string, siteStr: string, minutes: number) => {
                console.log(`site: ${siteStr}, minutes: ${minutes}`);
            }
        }],
    });
}

Match Function

For the most advanced cases, you can write a function that takes in transcripts as they come down the wire and return undefined when there's no match, or an array of arguments to pass to the pageFn when there is a match.

Use cases include:

  • Match based on something on the page
  • Match based on some internal plugin state
  • Regex matching

Cake walk.

We need to make match an object of type IDynamicMatch

How about a plugin for Gmail that moves the currently selected messages to a folder that the user commands to?

TIP

We could use the wildcard matching for this (eg. "move to *") but then we cant limit the user's choices to valid folders.

/// <reference path="../@types/plugin-interface.d.ts"/>
import { PluginBase } from '../PluginBase';

export module GmailPlugin {
    export let Plugin = Object.assign({}, PluginBase, {
        niceName: 'Gmail',
        match: /.*gmail.com/,
        commands: [{
            name: 'Move to Folder',
            description: 'Move already selected emails to a spoken folder',
            match: {
                description: 'Say "move to [folder name]"',
                fn: async (folderStr: string) => {
                    // if (folderStr in folders) {
                    //    ...
                    // }
                },
            },
            pageFn: async () => {
                // ...
            }
        }],
    });
}
Last updated: 12/5/2018, 4:37:16 AM