Solved: Alexa Echo Unable to Play Tunes By Artist

Alexa started offering a “station” every time I asked her to play tunes by an artist or to play a particular tune.

After a little investigation, I discovered it was one Echo impacted, out of the 5 in our home. Somehow, the one device seemed not to know we had a subscription that would permit us to request particular tunes. (I think it is our Prime subscription. I don’t think we have a deluxe music subscription.)

Rebooting the device and checking the software for the latest version did not change its behavior.

At any rate, the solution was to deregister and re-register that Echo. To do so:

  • Browse to https://alexa.amazon.com and login, if necessary.
  • Select “Settings”
  • Click on that particular Echo device, from the list of devices.
  • Scroll down to the “About” section and click “Deregister”.
  • Confirm that is what you want to do.
  • Now run and fetch your phone, because Registering can only be accomplished via the Alexa app on your phone.
  • Give the Echo 3 minutes to restart. If it hasn’t restarted on its own, power cycle it.
  • The Alexa app on your phone should prompt you to register the “new” device. Follow the wizard as it walks you through registering.

Why I'm Moving to IDrive

… despite it not meeting my requirements.

I need sync among my Win/Mac/Linux machines. I need off-site backup. I need on-site backup. I actually have all this right now, but it has too big a footprint.

I can sort of keep it going, but there is no way my wife would ever spend the effort, if I were temporarily disabled. I’m skeptical I could keep it going when I reach age 80. I need something simpler. And right now, my on-site backup is a beast of a server with triple-RAID for data and two-drive RAID for the OS. This is nuts.

My requirements:

  • Zero knowledge - Non-negotiable. The vendor doesn’t store files unencrypted and doesn’t have the encryption key.
  • Multiple sync folders. e.g. Not like OneDrive where everything to sync lives inside a “OneDrive” folder.
  • Mac/Win/Linux-386/Linux-ARM - my Mac, wife’s Windows laptop, a Linux server, a future Windows laptop for me.
  • Affordable. I’m flexible on the definition
  • Performance. Uploads/downloads happen quick enough for my 2TB of data. Software is low CPU/disk demand.
  • Selective sync. If I have 2 computers sharing an online folder, some files to sync with one and some with the other.
  • 3rd party backup. I can back it up to a 3rd party so I don’t need a local backup.
  • Supported.
  • Simplicity. Can I manage it when I’m 80? Can my wife get files out of it when I’m dead?

Nobody meets all of these as of April 2021. SpiderOak and Tresorit come pretty close. They are zero knowledge and multiple sync folders. At $288/year for 2.5 TB, Tresorit is more than I want to pay. SpiderOak is bearable at $150/year for 2TB, but if I grow beyond that, the next stop is $320 for 5TB. They don’t support Linux-ARM and they don’t support 2FA for web logins! Wow. I didn’t even know I needed to add that to my requirements.

iDrive looks like it meets all the requirements except multiple sync folders, for $70 per year for 5 TB, with first year under $10. Somebody even made it work with Linux-ARM. You might think you could get around the multiple sync folder issue with symlinks, but it simply ignores them. Some nut cases on the web suggest putting the real folders in the sync folder and linking to them from the other place you need them. Try that with subfolders of your /etc and let me know how it works for you!

I think I can get around the requirement for multiple sync folders. The files I sync with every machine are mostly kleinfelter-file-cabinet – a collection of ‘documents’ I share with my wife. Almost everything else I sync is synced with my server, where they get backed up locally and sent to my off-site backup provider electronically. I might like to sync some of my project folders, but they could be moved into a single sync folder.

iDrive handles backups separately from sync. You can backup from multiple source folders. To configure backups, launch the iDrive app (via “Start iDrive” on the menu bar icon). You can select all the folders you want via the “Change…” button. (Why can’t they let you add sync folders similarly?)

So I think I can live with everything to sync in a single sync folder, with backup of my other files. If I find otherwise, for Mac/Win/Linux-386 there is https://www.insynchq.com/pricing which says it adds features such as multiple sync folders (at the cost of increased complexity). Linux-ARM is SOL here, but my Linux ARM box will be solely used for backup. See this site for iDrive ARM backup tips.

rclone makes many things possible, but the complexity is off the charts, and it really only supports 1-way sync. They are very clear that setting up 2-way syncs risks data loss. I might wind up using rclone on my Linux-ARM because I can set up 1-way backup to run once a day and then forget it (except to confirm it is really still running).

I could use rclone to encrypt storage at OneDrive or any other unencrypted site via its “crypt” feature, but the complexity is just too much.

iDrive performance is pretty good. I observe upload is 12 MB/s. That’s 166,666 seconds for 2 TB; 2778 minutes; 46 hours; 2 days. That’s not bad. I got a response from their support in about 3 hours, so that’s tolerable.

SpiderOak Notes

  • Zero knowledge
  • Many sync folders
  • At $150/$320 for 2TB/5TB they are pricier than iDrive. Too pricey if I exceed 2TB.
  • They are otherwise a very fine solution
  • Their web site looks like consumer file sync might not be a big part of their marketing strategy any longer

OneDrive Notes

  • Not zero knowledge.
  • Single sync folder. Symlinks in the sync folder are screwy. The may sync from Microsoft to your computer but not vice versa. Looks like they use the Windows version of inotify, and that doesn’t work across symlinks.
  • At $100 per year for 6 users and 6TB, with free Word, Excel, Powerpoint, its a bargain, but since they don’t have iDrive’s work-around for backup, and they don’t protect my files with zero knowledge, I just can’t use them.
  • Must use 3rd party for linux. No apparent Linux-ARM.
  • boxcryptor encrypts. They do have Linux support (see “portable version”). It adds complexity.

Sync.com Notes

  • Multiple sync folders not supported and they don’t have iDrive’s work-around. They might work with symlinks, but they say it is unsupported.
  • $96/year for 2TB and $120 for 3TB is affordable.

Google Drive Notes

  • Not zero knowledge.
  • Multiple sync folders not supported and they don’t have iDrive’s work-around.
  • Too expensive beyond 1TB, and I need 2TB minimum. $240/$1200 for 2/10TB.

Dropbox Notes

  • Not zero knowledge.
  • Multiple sync folders not supported and they don’t have iDrive’s work-around.
  • Dropbox: via help.dropbox.com - “As of mid-2019, Dropbox no longer follows items outside of your Dropbox account that are linked to by a symlink.”

Other Candidates:

  • Tresorit, zero knowledge, many sync folders, at $288 for 2.5TB they are too rich for me.
  • Sync.com, zero knowledge, one sync folder but no iDrive-style work-around, $96/$120/$180 for 2/3/5TB
  • GoodSync, not zero knowledge, unknown sync folder count
  • CrashPlan, not zero knowledge, backup only, $120 for ‘unlimited’ storage
  • Syncplicity, not zero knowledge, unknown sync folder count, tiny storage limits
  • Jungle Disk, zero knowledge, unknown sync folder count, only trivial storage sizes listed
  • KeepVault, zero knowledge, unknown sync folder count, $1300 for 2TB!
  • Resilio, P2P only

Summary

So backup of any folder, single sync folder (ugh!), zero knowledge, affordable, performant, Win/Mac/Linux-386/Linux-ARM.

How to Find the MAC of Your Amazon Smartplug

Sometimes you need to know the MAC address or the IP of your Amazon Echo Smartplug. Here’s how to find it.

If I ruled the universe, the MAC address would be printed on the side of the smartplug. I don’t, so it isn’t.

If you view your router’s list of connected WiFi devices, and you look at just the smart-plug devices, you’ll see something like:

Name IP MAC
AmazonPlug3EXM 192.168.1.199 cc:9e:a2:00:21:07
AmazonPlug2EAM 192.168.1.157 cc:9e:a2:00:11:01
AmazonPlug4RPQ 192.168.1.59 cc:9e:a2:00:16:04
ESP_20BC42 192.168.1.202 3C:71:bf:18:32:44

Knowing it is “AmazonPlug4RPQ” isn’t much help. I need to know things like:

  • Which switch controls my fan?
  • Which switch turns on the Christmas tree lights?
  • Which switch turns on the bathroom nightlight?

My router’s device page shows how long it has been since a device received its DHCP lease. I walked from smartplug to smartplug, unplugging and re-plugging each device. I made a note of the sequence of my visits. Then I returned to the router DHCP lease time. All of the smart plugs had a lease which started less than 10 minutes ago. I noted the duration for each lease, and paired them up in the same order as my visit list. Viola!

If your router does not show the DHCP lease duration, here’s plan B:

  • ping each smart plug by IP address, to confirm they’re all online.
  • Unplug one smart plug. Ping each smart plug IP address, and see which one disappeared.
  • Plug the smart plug back in. Wait 10 seconds. Confirm it now pings.
  • Repeat the process for each smart plug.

If you have a label maker, print labels with each MAC address and label your smart plugs. Don’t bother to label with the IP address, because that can change over time, if your router has a whim. MAC address is permanent.


Keyword fodder: Amazon plug, Amazon smartplug, Amazon smart plug, Amazon Echo Plug, Amazon Echo Smartplug, Amazon switch, Amazon smart switch

Choosing a Bank

I recently had occasion to take a close look at my bank. Nothing wrong with my bank per se, but I chose it about 30 years ago and my situation and banking has changed over the years.

I want:

  • “High interest savings” - I’m going to put 3-6 months in an FDIC insured account in case there’s a major market melt-down. This covers everything except government melt-down.
  • Checking - I want my checking and savings at the same bank for easy inter-account shuffling.
  • Another free checking account elsewhere in case my main bank gets frozen. I’ll send my ACH debits and P2P e-transfers through here.
  • Free “Bill Pay”.

Candidates:

There are many good banks. I’m focusing on:

  • Alliant
  • Ally
  • Discover

These are all highly-rated by consumer reports and Reddit seems positive about them. There are others, but I want:

  • Full range of services
  • Among the higher savings rates
  • Among the higher customer satisfaction
  • Very good web site

“Very good” in all of these – not necessarily the best in any one category.

Detail Shopping List

Checks - no clear winner; Discover maybe a tad better

  • No per-check/per-transaction fee
    • Alliant: yes
    • Ally: yes
    • Discover: yes
  • How many free paper checks
    • Alliant: First ‘box’ free. (Reportedly 100 checks.)
    • Ally: Free. (Reportedly in lots of 20.)
    • Discover: Reportedly free forever
  • Criteria for no-fee checking
    • Alliant: $0 minimum balance; at least one electronic deposit per month; electronic statements only
    • Ally: $0 minimum balance
    • Discover: $0 minimum balance

Savings Account - no clear winner; Discover maybe a tad better

  • Interest rate on savings, Jan 1, 2020
    • Alliant: 1.62%
    • Ally: 1.6%
    • Discover: 1.7%
  • Criteria for no-fee savings
    • Alliant: electronic statements only
    • Ally:
    • Discover:
  • Current Savings rate with $1000 initial deposit, $100 minimum balance
    • Alliant:
    • Ally:
    • Discover:
  • How long to transfer from savings to checking
    • Alliant:
    • Ally:
    • Discover:

Bill Pay - no clear winner; Ally maybe a tad better (because people really like their web site).

  • Free Bill Pay
    • Alliant: some reports it is ‘clunky’
    • Ally: yes
    • Discover: yes
  • Bill Pay Uses MY account number or 3rd party:
    • Alliant:
    • Ally:
    • Discover:

Web Site - Ally

  • Transfer between accounts via web site
    • Alliant:
    • Ally:
    • Discover:
  • Web site quality:
    • Alliant: “It’s decent, a lot less buggy than my last CU’s app but there are definitely some room for UI improvements.” “Alliant has a dated website.”
    • Ally: “Ally has a sweet app/website”. * https://www.thebalance.com/best-online-checking-accounts-4158695 = “one place where Ally stands out is its online transfer options”
    • Discover:

e-payments - no clear winner

  • ACH Limits:
    • Alliant: Reportedly, can only push $25K/day and pull $100k/day.
    • Ally: Reportedly, Ally allows $150k push and $250k/pull.
    • Discover:
  • Works with Google Pay:
    • Alliant: Yes, via debit card.
    • Ally:
    • Discover:
  • Zelle
    • Alliant: no (work-around: Google Pay via their debit card)
    • Ally: yes
    • Discover: yes
  • Can I EFT to/from Schuler instead of Zelle. Can I do the allowance via ACH? (Or is Google Pay better?)
    • Alliant: Bill Pay paper check
    • Ally:
    • Discover:

Security/Fraud-prevention

  • 2FA
    • Alliant: yes, opt-in
    • Ally: yes, SMS
    • Discover: yes, SMS or email
  • Per-transaction text/email
    • Alliant: yes
    • Ally: “If you want to get instant push notifications about transactions you have to download a second app the goes with the first main bank app. This second app let’s you set push notification settings and control your debit card. “
    • Discover: ?
  • Other Security:
    • Alliant:
    • Ally:
    • Discover: When I set up Vanguard for ACH, Vanguard made micro-deposits to Discover overnight. Discover sent me an email at 4 AM to notify me of the deposits, explained they were typically for setting up ACH, and told me to contact them if I’d not done this.

Mobile Banking

  • Limits on mobile deposits
    • Alliant: $50,000 per day
    • Ally: $50,000 per day
    • Discover: $10K/day and $25K/month ($5K/day and $10K/month for first 90 days)

Service/Support

  • US-based call centers? Discover=Y, Ally=?, Alliant=?
    • Alliant:
    • Ally:
    • Discover:
  • Phone support hours
    • Alliant: 24/7
    • Ally: 24/7
    • Discover: 24/7
  • Online chat hours
    • Alliant: Can’t find chat. Phone oriented.
    • Ally: 24/7 - I waited < 2 minutes for a chat on New Years Day at 5 PM
    • Discover: Can’t find chat. Phone oriented.

ATM

  • 3 nearest ATM
    • Alliant: Allpoint (all over the place)
    • Ally: Allpoint (all over the place)
    • Discover: Allpoint + Moneypoint (all over the place)
  • Reimbursement/fee for other ATM
    • Alliant: Free at multiple networks; Up to $20 reimbursed
    • Ally: Free at Allpoint; up to $10 reimbursed
    • Discover: Free at Allpoint and MoneyPass; $0 reimbursed

Teen Checking

  • Alliant: Nerdwallet likes their teen checking. But, “The account also imposes low daily limits of $100 on cash withdrawals and $300 in spending.” When child turns 18, account converts to a standard checking account. But the joint account owners remain the same unless you apply for change. Maybe sign up for this WITHOUT a parent account?
  • Ally: Nothing at all. Can’t even open a joint account with teen.
  • Capital One 360 MONEY: Frequently cited as a ‘best’ teen account, but it does not allow writing checks.
  • Discover: ????
  • SunTrust: 4 years free; joint account with a parent if under 18.

Other

  • Current promo and criteria
    • Alliant:
    • Ally:
    • Discover:
  • Bonuses
    • Alliant: Reportedly can deposit cash at ATMs.
    • Ally: “Ally has a more modern website and mobile app. Ally’s mobile app also has a second card control app that you can use to disable your debit card, restrict transactions amounts and types of transactions as well as region lock purchases to only occur near your smart phone”
    • Discover:
  • Gotchas
    • Alliant: Not part of the national credit union network; cannot do Alliant banking at other credit unions. But someone says you CAN deposit at ATMs.
    • Ally:
    • Discover: Their debit card is Discover, not MasterCard/Visa.
    • Discover: New accounts (1st month) hold deposits for 7 business days.

Same UID in Docker Container and Host

Sometimes, it is convenient to have a UID in a Docker container match the UID in the host. You can’t do it all the time and it isn’t everyone’s cup of tea, but here’s how I made my MySQL user ID and gr

First, I always create a build script. i.e. Don’t just build your container from a Dockerfile via a straight command line. I call my build script “build-me.sh”. I also always use docker-compose. Tha

Here’s code from build-me.sh:

if ! id -u mysql ; then
    sudo groupadd -g 400 mysql
    sudo useradd -Ms /bin/false -u 400 -g mysql mysql
fi
MYSQLUID=`id -u mysql`
MYSQLGID=`id -g mysql`

If there is not already a mysql user, we’ll create one with UID and GID 400. You could use another number. I’ve just standardized on that one. Then, whether or not we created a UID, we retrieve the c

Here’s the build statement:

docker-compose build --build-arg MYSQLUID=$MYSQLUID --build-arg MYSQLGID=$MYSQLGID

And here’s an excerpt from Dockerfile:

FROM ubuntu:18.04
ARG MYSQLUID
ARG MYSQLGID
...
RUN id mysql || ( sudo groupadd -g 400 mysql &&  sudo useradd -Ms /bin/false -u 400 -g mysql mysql )
RUN apt-get -y install mysql-server

On Dying

This is about dying but not about death. It is about the word “dying”:

  • Dying = death (death is highly irregular, and it cuts life short)
  • Dyeing = coloring (coloring with dye is not irregular)
  • Dieing = cutting a shape with a die (cutting shapes is not irregular)

That’s how you can remember which of dying/dyeing/dieing you want. The irregular verb death is the irregular activity which cuts life (and the word) short.

;-)

node.js TiddlyWiki to Joplin

Migrating from TiddlyWiki to Joplin

I wanted to migrate my data from TiddlyWiki to Joplin. This documents how I got there. You will not like the results if you follow my steps exactly. You may find this document helpful if you use it as a guide in creating your own migration process.

My Setup:

  • I use the “anstosa” plugin for Markdown tiddler markup. (David Alfonso’s conversion uses the official Markdown plugin, not anstosa. They implement Markdown subsets.)
  • Most of my tiddlers are in Markdown.
  • My wikis are all run via node.js on a Linux box. This is named “boxtop3”.
  • My Joplin target will run on a Macbook.
  • I have about 2000 tiddlers.
  • I have lots of wiki links (intra-TiddlyWiki links). David’s conversion does not deal with these, leaving broken links when imported into Joplin. I fixed these with code (see below).
  • I have two TiddlyWikis. One is named PKB and the other DTL.

See this: https://davidalfonso.es/posts/migrating-from-tiddlywiki-to-markdown-files and this: https://gitlab.com/davidalfonso/tiddlywiki-migrator/tree/master

WARNINGS:

  • This process does not convert all legal Markdown. To do that, you’d have to fully parse the source files. The conversion does only string matching, so there are some edge cases where you have to just fix the source tiddlers to avoid.
  • This process does not deal with multiple stories having the same name. e.g. If you import TWO TiddlyWikis and each has a story called My Story, and there are wiki links to My Story, there’s no telling which of the two My Story your links will point to in Joplin. (This is not a problem for TiddlyWiki because wiki links point within the same wiki. It is a problem for Joplin because wiki-links are within Joplin, not within notebook.)
    • After you load Joplin, you can use “DB Browser for SQLite” to run this query to report on your duplicates:
select title,  count(*) from notes group by title having count(*) > 1  
and title != "DefaultTiddlers"
and title != "MarkupPreHead"
and title != "PageTemplate"

Preparing to Convert

  • (Optional:) Using TiddlyWiki in your browser, manually converted any remaining non-Markdown tiddlers to Markdown format.
    • This is a useful filter search to find Markdown tiddlers: [!field:type[text/x-markdown]!prefix[$:]!tag[OkNotMd]]
    • Except (You can tag these as OkNotMd):
      • AdvancedOptions
      • Configure Tiddler Subtitle
      • DefaultTiddlers
      • … and similar tiddlers which contain code or TW options.
    • The manual conversion to Markdown works for one of my TW where most tiddlers are Markdown, but I have an older wiki using TiddlyWiki markup: 4 are type text/vnd.tiddlywiki; 755 are type text/x-tiddlywiki; 90 are text/x-markdown.
    • For the old wiki, I manually convert text/vnd.tiddlywiki to Markdown.
  • I edited my tiddlers to remove all apostrophe and quote marks from tiddler titles. Take my word for it. You want to do this.

Converting

  • Download https://gitlab.com/davidalfonso/tiddlywiki-migrator/tree/master and unzip on your node.js server as ~/tiddlywiki-migrator
  • using the TW save button, save PKB to temp and move it to ~/tiddlywiki-migrator/wiki.html
  • Look in ~/tiddlywiki-migrator/node_modules/tiddlywiki/plugins/tiddlywiki/markdown/files/markdown.js
    • See (around line 395): jsonml.unshift.apply( jsonml, this.processBlock( m[ 1 ], [] ) );
    • That line is fragile about “——” (HR) in your tiddlers without a blank line before. you might want to make the code near there look like this in order to find bad tiddlers so you can manually fix them. See https://github.com/evilstreak/markdown-js/issues/17
      // if there's a leading abutting block, process it
      if ( m[ 1 ] ) {
        console.log('m1');
        console.log(m[1]);
        console.log('block');
        console.log(block);
        jsonml.unshift.apply( jsonml, this.processBlock( m[ 1 ], [] ) );
      }
  • The work-around is to edit any offending tiddlers to ensure ----- has a blank line before and after.
  • I prefer my file names to match the Tiddler titles. Edit scripts/safe-rename.js and make it look like this:
const fs = require('fs');
  
if (process.argv.length != 3) {
    console.log("Wrong parameters. Directory name expected.");
    process.exit(1);
}

const PATHNAME = process.argv[2].endsWith('/') ?
                 process.argv[2] : process.argv[2] + '/';

// List all filenames in dir received as argument
fs.readdir(PATHNAME, (err, files) => {
    if (err) throw err;
    files.forEach((filename) => {
        let newFilename = decodeURIComponent(filename);

        // Clean filename (CUSTOMIZE THIS)
        newFilename = newFilename
        // Remove accents/diacritics
        .normalize('NFD').replace(/[\u0300-\u036f]/g, "")
        // Convert separators to low line
        .replace(/\s+/g, '_')
        // Remove any non-safe character
        .replace(/[^0-9a-zA-Z-._]/g, "");

        fs.rename(PATHNAME + filename, PATHNAME + newFilename, (err) => {
            if (err) throw err;
        });
    });
});
  • The original puts YAML front matter on the .md files, and Joplin cant handle it, so edit the Makefile and remove these lines:

      @echo "---" > "$@"
      @cat "$(^:html=meta)" >> "$@"
      @echo "---" >> "$@"
    
  • Run: make * If it crashes on content, make sure evey Tiddler has valid syntax. (Using regular TW, open each tiddler without a JS crash.)
  • make convert
    • Somebody escaped the brackets in [[Title]]
      • The pandoc output has it.
      • The exported html does not.
      • Ergo pandoc added it.
      • I cant find a way to make pandoc stop.
      • i checked and my tw do not contain \[\ so it is safe to sed the Markdown.
    • Also, Yuck. Tiddlywiki output the html for triple backtick as <code></code>backtick both at the begining and at the end of the code block. Sometimes. I think the standard Markdown plugin cannot deal with single backtick inline code. Screw it. The MD converter plugin handles only Gruber MD, where triple backtick means something screwy. I’m just going to copy the Markdown tiddlers (where they exist) from TW into the output folder.
  • Put the following in ~/tiddlywiki-migrator/kpk-fixup.sh and run it.
# Rename files without the underscore so the names match the TW names
cd markdown_tiddlers
rename -v -e 's/_/ /g' *
cd ..

# For all the files created by the other guy's migration...
for f in markdown_tiddlers/*.md ; do

  # f2 = the node.js Tiddlywiki MARKDOWN file name
  f2="/data/tiddlywiki-sites/tw-node/pkb/tiddlers/`basename \"$f\"`"

  # Some older Tiddlers maybe got converted to Markdown, so they still have a .tid file type
  f3="${f2%%.md}.tid"
  
  # If TW has a .md file then use it.
  if [ -r "$f2" ] ; then
    echo cp "$f2" "$f"
    cp "$f2" "$f"
  else
    # if TW has no .md but it has a .tid, copy that IFF it is markdown format
    if [ -r "$f3" ] ; then
      echo "found $f3"
      if grep "type: text/x-markdown" "$f3" 1>/dev/null ; then
        echo "replace $f with $f3"
        
        # .tid files begin with metadata. The Markdown begins after a blank line.

        # Count how many lines to the first empty line
        var=`sed '/^$/q' "$f3" | wc -l`
        
        # Skip the empty line too
        var=$((var+1))
        tail -n +${var} "$f3" > "$f"
      fi
    fi
  fi
done
  • Get the underscores converted to spaces in the file names, and zip up the files for transfer to Mac:
cd markdown_tiddlers
rename -v -e 's/_/ /g' *
cd ..
tar -czvf markdown_tiddlers.tgz markdown_tiddlers/
  • On mac: scp kevin@boxtop:~/tiddlywiki-migrator/markdown_tiddlers.tgz markdown_tiddlers.tgz
  • This is pretty good except internal links import as [[Title]] but Joplin insists on using [Title](:/b9d7acbfa256439c8e92e018d0ebb1b7) as internal links.

  • Update the database to fix the internal links. You can’t do this until after the import, because the GUID are not assigned until the files are imported.
  • Database is in ~/.config/database.sqlite
  • code is in /Users/kevin/Sync/code/python/joplin
  • I’m using Python 3
  • Run: tw-to-joplin-links.py (code is shown below)

#!/usr/bin/env python
import re
import sqlite3

# Converts TiddlyWiki [[Link]] to Joplin's  [Link](:/GUID]

JOPLINDB = '~/.config/joplin-desktop/database.sqlite'

def no_commas(s):
    return s.replace(',', '')

# Some Titles look like Word%20With%20Spaces.
def decode_title(s):
    s2 = s.replace('%20', ' ')     # string.replace is a global replace-all-occurrences
    return s2

conn = sqlite3.connect(JOPLINDB)
c = conn.cursor()

c.execute("DELETE FROM notes where title = 'favicon.ico' or title = 'DefaultTiddlers' ")
c.execute("DELETE FROM notes where title = 'MarkupPreHead' or title = 'PageTemplate' ")

c.execute('SELECT title, id FROM notes')
rows = c.fetchall()
title_id = dict(rows)

# These may convert poorly. Mabe the [[foo]] is like this and should not be converted:  ```[[foo]]```
c.execute("SELECT id, body, title from notes where body like '%```%[[%```' order by title")
rows = c.fetchall()
for r in rows:
    print("WARNING:", r[2], "has [[ INSIDE ``` and may convert poorly")

# replacing [[AltTitle|Title]] with [AltTitle](:/ID)
c.execute("SELECT id, body, title FROM notes WHERE BODY LIKE '%[[%]]%' ORDER BY title")
rows = c.fetchall()

# Non-backtick, followed by [[blahblah]]
# This will fail to convert if the first 2 characters in the document are [[
reg1 = r"[^`]\[\[(.*?)\]\]"

for r in rows:
    matched1 = False
    body = r[1]
    my_title = r[2]
    print("Current story:", my_title)
    match = re.search(reg1, body)
    while match:
        print("Processing Markdown wiki link:", my_title)
        matched1 = True
        m = match.group(1)
        m2=re.search(r"(.+)\|(.+)",m)  # This one should be greedy because m contains only the content between [ ond ]
        if m2:
            # [alt_title|real_title]
            alt_title = m2.group(1)
            title = decode_title(m2.group(2))
            print("DEBUG processing alternate name wiki link. visible name=", alt_title, "internal name=", title)
        else:
            # [real_title]
            title = m
            alt_title = decode_title(title)

        #print("DEBUG lookup ID for title", title)
        if no_commas(title) in title_id:
            guid = title_id[no_commas(title)]
        else:
            guid = "LINK_TARGET_MISSING"
            print("WARNING:", my_title, "has a wiki link to missing document", title )

        # replace match.group(0) in r with [alt_title](:/GUID-of-title)
        s = match.group(0)[0]  # The 1-character not-backtick before the [
        newstring = s + "[" + alt_title + "](:/" + guid + ")"
        body = body.replace(match.group(0), newstring , 1)
        print("DEBUG replaced", match.group(0), "with", newstring)
        match = re.search(reg1, body)

    if matched1:
        escaped_body = body.replace("'", r"''")
        cmd = "UPDATE notes SET body = '" + escaped_body + "' WHERE id = '" + r[0] + "'"
        c.execute(cmd)

# replacing [Title](#Blah%20Blah) [Title](:/ID)
# You get these when the other guy's code exports tiddlywiki classic wiki links.
c.execute("SELECT id, body, title FROM notes WHERE BODY LIKE '%[%](#%)%' ORDER BY title")
rows = c.fetchall()

# Not backtick, followed by...
# This will fail if the first characters in the document are [
reg1 = r"[^`]\[.+?\]\(#(.+?)\)"

for r in rows:
    matched1 = False
    body = r[1]
    my_title = r[2]
    print("Current story:", my_title)
    match = re.search(reg1, body)
    while match:
        print("Processing TW wiki link:", my_title)
        matched1 = True
        m = match.group(1)

        title = decode_title(m)

        #print("DEBUG lookup ID for title", title)
        if no_commas(title) in title_id:
            guid = title_id[no_commas(title)]
        else:
            guid = ""


        # replace match.group(0) in r with [alt_title](:/GUID-of-title)
        # The other guy's export forces CamelCase wiki links, even if not enabled in TW.
        # That leads to a lot of link-not-found.  Just remove the hyperlink if link-not-found.
        s = match.group(0)[0]  # The 1-character not-backtick before the [
        newstring = s + "[" + title + "](:/" + guid + ")"
        if guid == "":
            body = body.replace(match.group(0), s + title)
            print("DEBUG replaced", match.group(0), "with", s + title)
        else:
            body = body.replace(match.group(0), newstring , 1)
            print("DEBUG replaced", match.group(0), "with", newstring)


        match = re.search(reg1, body)

    if matched1:
        escaped_body = body.replace("'", r"''")
        cmd = "UPDATE notes SET body = '" + escaped_body + "' WHERE id = '" + r[0] + "'"
        c.execute(cmd)


conn.commit()
conn.close()

print("FINISHED")

Done.

Short, Step-by-step - After You Did All the Setup

On Mac:

  1. Save DTL as ~/temp/dtl.html
  2. Save PKB as ~/temp/pkb.html
if [ `uname` = Darwin ] ; then
  cd ~/temp
  scp dtl.html kevin@boxtop3.home:dtl.html
  scp pkb.html kevin@boxtop3.home:pkb.html
fi

On boxtop3, from ~/tiddlywiki-migrator:

First - BOXTOP BOXTOP BOXTOP!

if [ `uname` = Linux ] ; then
  cd ~/tiddlywiki-migrator
  cp ../dtl.html wiki.html
  rm -rf tmp_wiki markdown_tiddlers
  make
  make convert
  ./kpk-fixup.sh
fi

Second

if [ `uname` = Linux ] ; then
  cd markdown_tiddlers
  rename -v -e 's/_/ /g' *
  cd ..
  tar -czf dtl_tiddlers.tgz markdown_tiddlers/
fi

Third

if [ `uname` = Linux ] ; then
  cp ../pkb.html wiki.html
  rm -rf tmp_wiki markdown_tiddlers
  make
  make convert
  ./kpk-fixup.sh
  tar -czf pkb_tiddlers.tgz markdown_tiddlers/
fi

On Mac, from ~/temp:

if [ `uname` = Darwin ] ; then
  rm -rf dtl_tiddlers  pkb_tiddlers dtl_tiddlers.tgz  pkb_tiddlers.tgz
  scp kevin@boxtop3.home:~/tiddlywiki-migrator/dtl_tiddlers.tgz dtl_tiddlers.tgz
  scp kevin@boxtop3.home:~/tiddlywiki-migrator/pkb_tiddlers.tgz pkb_tiddlers.tgz
fi
if [ `uname` = Darwin ] ; then
  tar zxvf dtl_tiddlers.tgz
  mv markdown_tiddlers dtl_tiddlers
  tar zxvf pkb_tiddlers.tgz
  mv markdown_tiddlers pkb_tiddlers
fi
  1. Using Joplin, import dtl_tiddlers
  2. Using Joplin, import pkb_tiddlers
  3. Run on Mac, from /Users/kevin/Sync/code/python/joplin:
    1. . python-chooser
    2. tw-to-joplin-links.py
  • And check your results in Joplin:
    • Check some general page layouts in DTL
    • Check some wiki links in DTL
    • Check some general page layouts in PKB
    • Check some wiki links in PKB

Turn Off Notifications for SMS From One Contact

I wanted to turn off notifications for text messages from some senders. This has changed over the years. Here’s how it works on my phone today. I think I’m on Android 8 (Oreo).

  • Navigate to the list of conversations in Messages
  • Open a thread with the desired sender
  • Click the menu icon (3 dots)
  • Choose Details
  • Choose Notifications
  • Turn off the “Show notifications” switch

Dear Marie Kondo

Dear Marie Kondo,

Clothes do not bring me joy. I simply do not give a damn about socks, shirts, pants, briefs. Following your advice to retain only items which spark joy, I am now nude and unemployed. Of course, since I was the breadwinner for my family, my wife and children have left me. They brought me joy, but discarding my clothing was important to reducing my clutter, and now I’ve certainly reduced my clutter.

Oh, and thank heavens I got rid of those clothes. I saw many pictures of drawers full of folded clothing stored vertically. That really does work well for a drawer full of clothing. But my drawers were full of clothing only immediately after I washed. By mid-week, they were only half full! Of course, whenever I opened a half full drawer of shirts stored vertically, they fell over. It was so much bother to stand them up each time I opened the drawer. I considered using bookends to keep them tidy, but bookends do not bring me joy.

I had many tools which I’ve discarded. I really didn’t get joy from my lawn mower or the table saw and other tools. Now the city mows my lawn for me. They fine me only $2500 each time they mow it, so I’m getting rid of the clutter of cash too! Of course, without the table saw and other tools, there are some home repairs I can’t perform. But that’s OK. My home has been condemned by the city, so it too will be discarded.

Oy! Don’t get me started about eating utensils. Is there really someone who derives joy from a fork or a spoon? But now that I’m losing my home, I won’t really have to bother with utensils. Chez Dump lets one eat with one’s fingers.

Camping used to bring me joy, but it has so many items one must store. There really isn’t any way to store 432 items vertically. I used to store them in stacked containers. Of course they overflowed the available space. When I looked at each individual item, I had to admit that most of them did not bring me joy in and of themselves. Picking up my nifty little camp stove does bring me joy because it is so well designed. Fuel bottles – not so much joy. So now I go camping in the nude with just my stove and no fuel. I’ve certainly reduced my clutter.

I used to enjoy ham radio as a hobby. I really, really love my Elecraft KX3 radio. It is epically well designed. But to be honest, things like batteries to run it, wires to connect it to the batteries, antennas, microphones… not so much. Now that I got rid of all of those critical accessories, I do still love my radio. Do you have any advice on how I can use my radio without power or a microphone? No? Well, I’ll just appreciate what it used to do for me.


Frankly, problems with the whole Kondo method include

  • It assumes that one lives in a managed apartment with all maintenanced attended to by someone else
  • One has no hobbies which come with lots of stuff. (Hobbies bring joy.)
  • One’s drawers are always at a constant level of fullness. (Vertical topples unless supported.)
  • One derives joy from items necessary to meet one’s responsibilities. (There’s a whole lot of shit I have to own in order to maintain my house, my car, my job, my dental health.)

The Kondo method seems well suited to someone with clothing and housewares fetishes, no hobbies, and no responsibilities.