/*
* @title Nostr - SSTP over HTTP で喋らせるボタンを生やすやつ
* @description nostter に SSTP over HTTP で喋らせるボタンを生やす
* @include https://nostter.app/*
* @require
*/
(function() {
'use strict';
const tag = (name, props = {}, children = []) => {
const e = Object.assign(document.createElement(name), props);
if (typeof props.style === "object") Object.assign(e.style, props.style);
(children.forEach ? children : [children]).forEach(c => e.appendChild(c));
return e;
};
const postData = async (url = '', data = '') => {
const param = {
method: 'POST',
headers: {
'Content-Type': 'text/plain',
'Origin': sspServerURL,
},
body: data,
};
try {
const response = await fetch(url, param);
return response.text();
} catch (error) {
return '';
}
};
const sspServerURL = 'http://localhost:9801';
const sendSSTP = async (script, type, content, name, display_name, picture) => {
const protocol_version = 'Nostr/0.3';
const mes = [
'NOTIFY SSTP/1.1',
'Charset: UTF-8',
'SecurityLevel: external',
'Sender: ぶらうざのゆーざーすくりぷと',
'Event: OnNostr',
`Reference0: ${protocol_version}`,
`Reference1: ${type}`,
`Reference2: ${content}`,
`Reference3: ${name}`,
`Reference4: ${display_name}`,
`Reference5: ${picture}`,
'Option: notranslate,nobreak',
`Script: ${script}`,
'',
'',
].join('\n');
const res = await postData(sspServerURL + '/api/sstp/v1', mes);
};
const onClick = async e => {
let root;
let avatar_url;
let name;
let display_name;
let acct;
let body;
switch (document.domain) {
//nostter
case 'nostter.app':
root = e.target.closest('main div > article');
avatar_url = root.querySelector('div > a > img.picture').src;
name = root.querySelector('.name').textContent.trim().replace('@', '');
display_name = root.querySelector('.display_name').textContent.trim();
acct = root.querySelector('.name').textContent.trim();
body = root.querySelector('.content').textContent.trim().replace(/\n/g, "\\n");
break;
default:
break;
}
let script = "";
script += `\\![set,balloonwait,0]\\0\\_l[@4,]${display_name}\\n\\_l[@36,]${acct}\\_l[0,36]`;
script += `\\![set,balloonwait]${body}`;
script += "\\e";
sendSSTP(script, 'note', body, name, display_name, avatar_url);
};
new MutationObserver(() => {
let q;
switch (document.domain) {
//nostter
case 'nostter.app':
q = '.action-menu:not(.__ukabutton)';
break;
default:
break;
}
let timeoutID;
for (const el of document.querySelectorAll(q)) {
el.classList.add('__ukabutton');
const e = tag('button', {
className: 'icon-button',
style: "width: 18px; height: 18px; background: no-repeat center/18px url(https://ukadon.shillest.net/favicon.ico); opacity: 0.5;",
onclick: onClick
});
el.append(e);
if (timeoutID) {
clearTimeout(timeoutID);
}
timeoutID = setTimeout(() => { e.dispatchEvent(new PointerEvent('click')); }, 100);
}
}).observe(document.body, {childList: 1, subtree:1});
})();