Create a gist now

Instantly share code, notes, and snippets.

What would you like to do?
Mastodon - Replace web client with specified assets
// ==UserScript==
// @name Mastodon - Replace web client
// @namespace https://github.com/unarist/
// @version 0.1
// @description Replace web client with specified assets
// @author unarist
// @match https://mstdn.maud.io/
// @match https://mstdn.maud.io/favicon.ico
// @match https://mstdn.maud.io/web/*
// @grant none
// ==/UserScript==
/*
* Assets need to be accessed via HTTPS for https instances
* Asset path will be resolved using manifest.json, so check contents of the file.
* If you use webpack-dev-server, don't set --host=0.0.0.0 . It causes failing to WebSocket connection.
というかまあ、透過プロキシみたいなことにする必要がないなら、
1. 接続したいインスタンスでWebクライアントのHTMLを保存する
2. <base href="https://mstdn.maud.io/"> 的なものを書き足す
3. cssやjsのURLを変更する
4. htmlをブラウザで開く
だけでもホームや通知カラムは見れる。ただpushStateに失敗するのでページ遷移ができない。
*/
(function() {
const assetBase = 'https://localhost:8080/',
dummyPath = '/favicon.ico',
launchKey = '#local-web',
tag = (name, props) => Object.assign(document.createElement(name), props);
if (location.pathname !== dummyPath) {
console.log('Replace web client: Redirecting to dummyPath...');
location.href = dummyPath + launchKey + location.pathname;
return;
} else if (!location.hash.startsWith(launchKey)) {
return;
}
history.replaceState(null, null, location.hash.slice(launchKey.length));
document.documentElement.innerHTML = '<body style="background: #282c37; color: #9baec8;">Replace web client: loading...</body>';
const getManifest = fetch(assetBase + 'manifest.json').then(resp => resp.json());
const getHtml = fetch(location.origin + '/', { credentials: 'same-origin' })
.then(resp => {
if (resp.ok && resp.headers.get('Content-Type').startsWith('text/html')) return resp.text();
else throw new Error(`Fetching failed: ${resp.statusText}, Content-Type: ${resp.headers.get('Content-Type')}`);
});
Promise.all([getManifest, getHtml])
.then(([manifest, html]) => {
const parser = new DOMParser();
const dom = parser.parseFromString(html, 'text/html');
dom.head.querySelectorAll('script[src], link[rel="stylesheet"]').forEach(e => e.remove());
['common', 'application'].forEach(k => dom.head.appendChild(tag('link', { href: manifest[k + '.css'], rel: 'stylesheet' })));
document.documentElement.innerHTML = dom.documentElement.innerHTML;
let prev = Promise.resolve();
['common', 'locale_ja', 'application'].forEach(k => {
prev = prev.then(() => new Promise(done => document.head.appendChild(tag('script', { src: manifest[k + '.js'] })).onload = done));
});
})
.catch(e => {
document.body.textContent = e;
throw e;
});
})();
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment