この記事は、Firefox 57以降へ移行する際のアドオン(拡張機能)周りについて書いていたメモ書きです。 Firefox 57では、拡張機能の仕組みとしてXULが廃止(拡張機能としては使えなくなり)され、WebExtensionsベースのものへと刷新されました。

Firefox 56以下で動いていたアドオンの大部分は互換性がないため、Firefox 57+では新しい拡張機能への移行する必要がありました。

この記事では、拡張からアプリへ移行したり、同じような機能をもった拡張機能へ移行したりといった設定について書いています。

現在環境(2018年1月ぐらい)

  • (一時的に)Firefox 56の時のプロファイルをFirefox ESRで動作中
  • Firefox ESRがデフォルトブラウザの状態
  • Firefox ESRとFirefoxは同時に起動できない(Developer Editionみたいに分かれてない)

Firefox 57+への移行する

新しいプロファイルの作成

Firefox 57+向けに新しいプロファイルを作成し、その環境へ新規で環境を作っていく。 (既存の引き継ぐと壊れたりするので新しいプロファイルを作成する)

Firefox 57+を新しいプロファイルで起動する。 (-no-remoteを付けてESRと同時に起動して確認しながら進める)

-P で起動するとプロファイル画面がでるので、新しいプロファイルを作成して起動する。

$ /Applications/Firefox.app/Contents/MacOS/firefox-bin -P -no-remote

アカウントでログイン

  • Firefox アカウントでログインして"拡張機能"以外を同期する
  • デフォルトで"拡張機能"の同期は外れていた

拡張の対応

Karabiner

Karabinerで次のような感じのルールをrulesに追加してる。(Firefox向け部分のみ抜粋)

  • Cmd + Shift + J: 次のタブ
  • Cmd + Shift +K: 前のタブ
  • Cmd + n: タブを閉じる(ホントはタブを閉じて次のタブへのショートカット)
  • Cmd + Shift + c: これはgaiyasのショートカットがシステムとかぶって潰れたので無理やりみたいな感じのやつだった気がする
{
    "description": "Firefox shortcuts",
    "manipulators": [
        {
            "conditions": [
                {
                    "bundle_identifiers": [
                        "^org\\.mozilla\\.firefox$",
                        "^com\\.google\\.Chrome$",
                        "^com\\.apple\\.Safari$"
                    ],
                    "type": "frontmost_application_if"
                }
            ],
            "from": {
                "key_code": "j",
                "modifiers": {
                    "mandatory": [
                        "left_command"
                    ]
                }
            },
            "to": [
                {
                    "key_code": "backslash",
                    "modifiers": [
                        "left_command",
                        "shift"
                    ]
                }
            ],
            "type": "basic"
        },
        {
            "conditions": [
                {
                    "bundle_identifiers": [
                        "^org\\.mozilla\\.firefox$",
                        "^com\\.google\\.Chrome$",
                        "^com\\.apple\\.Safari$"
                    ],
                    "type": "frontmost_application_if"
                }
            ],
            "from": {
                "key_code": "k",
                "modifiers": {
                    "mandatory": [
                        "left_command"
                    ]
                }
            },
            "to": [
                {
                    "key_code": "close_bracket",
                    "modifiers": [
                        "left_command",
                        "shift"
                    ]
                }
            ],
            "type": "basic"
        },
        {
            "conditions": [
                {
                    "bundle_identifiers": [
                        "^org\\.mozilla\\.firefox$"
                    ],
                    "type": "frontmost_application_if"
                }
            ],
            "from": {
                "key_code": "n",
                "modifiers": {
                    "mandatory": [
                        "left_command"
                    ]
                }
            },
            "to": [
                {
                    "key_code": "w",
                    "modifiers": [
                        "left_command"
                    ]
                }
            ],
            "type": "basic"
        },
        {
            "conditions": [
                {
                    "bundle_identifiers": [
                        "^org\\.mozilla\\.firefox$"
                    ],
                    "type": "frontmost_application_if"
                }
            ],
            "from": {
                "key_code": "c",
                "modifiers": {
                    "mandatory": [
                        "left_shift",
                        "left_command"
                    ]
                }
            },
            "to": [
                {
                    "key_code": "c",
                    "modifiers": [
                        "left_shift",
                        "left_option"
                    ]
                }
            ],
            "type": "basic"
        }
    ]
}

Greasemonkey

Greasemonkey 4ではAPIの互換性がないため、大半のスクリプトがそのままでは動かない。

互換実装としては2つあり、Tampermonkeyはライセンスが不明なのでViolentmonkeyを選択

Greasemonkey to Violentmonkey

TampermonkeyとViolentmonkeyどちらもzipインポートをサポートしてる。 これを利用して既存のuser.jsをコピーして、まとめたzipを作成してimportする。

UserChrome.js

無理やりFirefox 57+でも動かせる(結局使ってない)

の2つを合わせると、インストールフォルダをいじらずにプロファイルフォルダだけの追加でUserChrome.jsを動かせる。

UserChrome Loaderのセットアップ

profileDir="~/Library/Application Support/Firefox/Profiles/プロファイル名"
chromeDir="${profileDir}/chrome"
mkdir "${chromeDir}"

# userChrome.xmlを読み込むuserChrome.css
curl https://raw.githubusercontent.com/nuchi/firefox-quantum-userchromejs/master/userChrome.css > "${chromeDir}/userChrome.css"
# userChrome.jsを読み込むuserChrome.xml -moz-bind
curl https://raw.githubusercontent.com/nuchi/firefox-quantum-userchromejs/master/userChrome.xml > "${chromeDir}/userChrome.xml"
# http://wiki.nothing.sh/page/userChrome.js%CD%D1%A5%B9%A5%AF%A5%EA%A5%D7%A5%C8#wd355e7f
# Loader
curl https://raw.githubusercontent.com/Endor8/userChrome.js/master/userChrome/Dateien/userChromeJS.js > "${chromeDir}/userChrome.js"
## どこにある*.us.jsを読み込むかを追加
echo 'userChrome.import("*", "UChrm");' >> "${chromeDir}/userChrome.js"

UserChromeスクリプト

UserChromeのスクリプトも同じく ${chromeDir}/ に配置していくとuserChrome.js* にマッチするファイルを読み込んでくれる。

profileDir="~/Library/Application Support/Firefox/Profiles/プロファイル名"
chromeDir="${profileDir}/chrome"
mkdir "${chromeDir}"

# 再起動ボタンの追加
curl https://raw.githubusercontent.com/alice0775/userChrome.js/master/addRestartButton.uc.js > "${chromeDir}/addRestartButton.uc.js"
# http://d.hatena.ne.jp/Griever/20091119/1258643086
curl https://gist.githubusercontent.com/Griever/238742/raw/8f54f0b916e9e43112a78f41ee52eabfa5ae63f6/KeyChanger.uc.js > "$chromeDir/KeyChanger.uc.js"

参考

keysnail

同等のことができるAPIは存在しない(Chromeができないのと同じ理由)

JKスクロール Scrollet

JとKでページスクロールする

ショートカット基盤が欲しい。Chrome権限レベルのAPIがない

Surfingkeysを使い、次のような設定をして JKスクロールをしている。(全部の設定が混ざってる)

settings.smoothScroll = false;
settings.scrollStepSize = 100;
settings.blacklistPattern = /^(https?:\/\/irodr\.netlify\.com|https?:\/\/localhost:13245)/
// copy(Array.from(new Array(40)).map((e,i) => String.charCodeAt("a") + i).map(code => String.fromCharCode(code)).map(key => `unmap("${key}");`).join("\n"))
unmap("a");
unmap("b");
unmap("c");
unmap("d");
unmap("e");
unmap("f");
unmap("g");
unmap("h");
unmap("i");
// unmap("j");
// unmap("k");
unmap("l");
unmap("m");
unmap("n");
unmap("o");
unmap("p");
unmap("q");
unmap("r");
unmap("s");
unmap("t");
unmap("u");
unmap("v");
unmap("w");
unmap("x");
unmap("y");
unmap("z");
unmap("{");
unmap("|");
unmap("}");
unmap("~");
unmap("/");
mapkey('<Meta-e>', 'Open postem', function() {
    location.href = `postem://?url=${encodeURIComponent(window.top.location.href)}&title=${encodeURIComponent(window.top.document.title)}`
});
mapkey('<Meta-Shift-Enter>', 'Open post-tweet', function() {
    const selectedText = window.getSelection().toString();
    location.href = `post-tweet://?url=${encodeURIComponent(window.top.location.href)}&title=${encodeURIComponent(window.top.document.title)}&quote=${encodeURIComponent(selectedText)}`
});
// cmd+n = cmd+w
map('<Meta-n>', '<Meta-w>');
// Space Scroll
map('<Space>', 'j');
map('<Shift-Space>', 'k');
// set theme
settings.theme = `
.sk_theme {
    background: #000;
    color: #fff;
}
.sk_theme tbody {
    color: #fff;
}
.sk_theme input {
    color: #d9dce0;
}
.sk_theme .url {
    color: #2173c5;
}
.sk_theme .annotation {
    color: #38f;
}
.sk_theme .omnibar_highlight {
    color: #fbd60a;
}
.sk_theme ul>li:nth-child(odd) {
    background: #1e211d;
}
.sk_theme ul>li.focused {
    background: #4ec10d;
}`;
// click `Save` button to make above settings to take effect.1

はてなブックマーク検索 Hatebnail

KeysnailではHatebnailというローカルに持ったはてなブックマークのDBを検索するものを使っていた。 しかし、Keysnailが動かなくなったため、はてなブックマークのインクリメンタル検索をするFirefoxの拡張がなくなった。

Alfred上で自分のはてなブックマークを検索できるWorkflow | Web Scratchも書いたけど、速さが足りなかった(プロセスの仕組み的にメモリに乗せられない)

拡張機能だとOnline Bookmark Incremental Search for Firefoxも良さそう。

最終的にはてなブックマーク検索PWAを書いて使っている。 Electronアプリでラップしてアプリとして利用。モバイルでも動作するので満足。

外部プロセス起動

ブラウザの拡張に依存するのはキケンであるため、URLとタイトルを渡してアプリを起動するのに使う。 TombfixはFirefox 57+では動かないので、自分でクロスポストクライアントとしてpostemというElectronアプリを書いて利用している。

現時点(2019-02-07)ではブラウザとアプリを中継するAPIがFirefoxにはない。

  • [ ] 汎用的な仕組みを持った拡張機能はまだない

URL scheme

macなどシステム側のprotocolにアプリを登録すれば、ブラウザから任意のアプリに情報を渡せるようになる。 以下のアプリはこの仕組みを使って、ブラウザからアプリを起動して使えるようにした。

postemは自分で書いているのでアプリ側でcustom protocolsに対応することで対応できる postem://post?title=<title>&url=<url> のようなURLに対応する。 FirefoxからカスタムプロトコルのURLを開くだけで起動できる。

これと同様にTwitterに投稿するpost-tweetというクライアントアプリを書いて使っている。

どちらも今見ているサイトに関する投稿を行うクライアントアプリ。

まとめ

使っているFirefoxの拡張はだいぶへった。 代わりになる拡張機能がないものものは自分で作った。

ChromeのManifest v3などまだ拡張機能自体は色々Breaking Changeがありそうなので、アプリに移行できるものはアプリに移行した。(そのために書いたアプリが増えた) 現在のブラウザの拡張の仕組みはどのブラウザでも大きな差がないので、ブラウザが変わった場合でも大まかな動きは変わらなくなっている気はする。

参考