nostr bookmark

    @@ -131,8 +131,7 @@ const naddr = window.NostrTools.nip19.naddrEncode({ identifier, kind, - pubkey, - relays: relaysToWrite + pubkey }); const urlToOpen = `https://nostr-web-bookmark-trend.vercel.app/${naddr})}`; location.href = urlToOpen;
  • /*
     * @title nostr bookmark
     * @description 現在のWebページをNostrでブックマーク
     * @include http://*
     * @license CC0 1.0
     * @require
     */
    
    (() => {
    	const nostrToolsUrl = 'https://unpkg.com/nostr-tools/lib/nostr.bundle.js';
    	const profileRelay = 'wss://directory.yabu.me/';
    	const now = Math.floor(Date.now() / 1000);
    
    	const getPubkey = async () => {
    		let pubkey;
    		if (window.nostr?.getPublicKey) {
    			try {
    				pubkey = await window.nostr.getPublicKey();
    			} catch (error) {
    				console.warn(error);
    			}
    		}
    		return pubkey;
    	};
    
    	const getReplaceableEvent = (pool, relays, filter) => {
    		return new Promise((resolve) => {
    			let event;
    			const sub = pool.subscribe(relays, filter, {
    				onevent(ev) {
    					if (event === undefined || event.created_at < ev.created_at) {
    						event = ev;
    					}
    				},
    				oneose() {
    					sub.close();
    					resolve(event);
    				}
    			});
    		});
    	};
    
    	const getRelaysToUseFromKind10002Event = (event) => {
    		const newRelays = {};
    		for (const tag of event?.tags.filter(
    			(tag) => tag.length >= 2 && tag[0] === 'r' && URL.canParse(tag[1])
    		) ?? []) {
    			const url = window.NostrTools.utils.normalizeURL(tag[1]);
    			const isRead = tag.length === 2 || tag[2] === 'read';
    			const isWrite = tag.length === 2 || tag[2] === 'write';
    			if (newRelays[url] === undefined) {
    				newRelays[url] = {
    					read: isRead,
    					write: isWrite
    				};
    			} else {
    				if (isRead) {
    					newRelays[url].read = true;
    				}
    				if (isWrite) {
    					newRelays[url].write = true;
    				}
    			}
    		}
    		return newRelays;
    	};
    
    	const getRelays = (relayRecord, relayType) => {
    		return Array.from(
    			new Set(
    				Object.entries(relayRecord)
    					.filter(([_, obj]) => obj[relayType])
    					.map(([relay, _]) => relay)
    			)
    		);
    	};
    
    	const main = async () => {
    		const pubkey = await getPubkey();
    		if (pubkey === undefined) {
    			return;
    		}
    		const url = new URL(location.href);
    		url.search = '';
    		url.hash = '';
    		const identifier = url.href
    			.replace(/#$/, '')
    			.replace(/\?$/, '')
    			.replace(/^https?:\/\//, '');
    		const pool = new window.NostrTools.SimplePool();
    		const event10002 = await getReplaceableEvent(pool, [profileRelay], {
    			kinds: [10002],
    			authors: [pubkey],
    			until: now
    		});
    		const rr = getRelaysToUseFromKind10002Event(event10002);
    		const relaysToRead = getRelays(rr, 'read');
    		const relaysToWrite = getRelays(rr, 'write');
    		const kind = 39701;
    		const event39701 = await getReplaceableEvent(pool, relaysToRead, {
    			kinds: [kind],
    			authors: [pubkey],
    			'#d': [identifier],
    			until: now
    		});
    		const content = prompt('コメントを入力してください。', event39701?.content);
    		if (content === null) {
    			return;
    		}
    		const tags = event39701?.tags ?? [
    			['d', identifier],
    			['published_at', String(now)],
    			['title', document.title]
    		];
    		const eventTemplate = {
    			content,
    			kind,
    			tags,
    			created_at: now
    		};
    		const signedEvent = await window.nostr.signEvent(eventTemplate);
    		if (
    			!window.confirm(`以下のリレーに送信します。よろしいですか?\n${relaysToWrite.join('\n')}`)
    		) {
    			return;
    		}
    		await Promise.any(pool.publish(relaysToWrite, signedEvent));
    		if (!window.confirm('送信完了しました。ブックマークページを開きますか?')) {
    			return;
    		}
    		const naddr = window.NostrTools.nip19.naddrEncode({
    			identifier,
    			kind,
    			pubkey
    		});
    		const urlToOpen = `https://nostr-web-bookmark-trend.vercel.app/${naddr})}`;
    		location.href = urlToOpen;
    	};
    
    	affixScriptToHead(nostrToolsUrl, main);
    
    	//https://developer.mozilla.org/ja/docs/Web/API/HTMLScriptElement のコピペ
    	function loadError(oError) {
    		throw new URIError(`スクリプト ${oError.target.src} は正しく読み込まれませんでした。`);
    	}
    
    	function affixScriptToHead(url, onloadFunction) {
    		const newScript = document.createElement('script');
    		newScript.onerror = loadError;
    		if (onloadFunction) {
    			newScript.onload = onloadFunction;
    		}
    		document.head.appendChild(newScript);
    		newScript.src = url;
    	}
    })();
    
  • Permalink
    このページへの個別リンクです。
    RAW
    書かれたコードへの直接のリンクです。
    Packed
    文字列が圧縮された書かれたコードへのリンクです。
    Userscript
    Greasemonkey 等で利用する場合の .user.js へのリンクです。
    Loader
    @require やソースコードが長い場合に多段ロードする Loader コミのコードへのリンクです。
    Metadata
    コード中にコメントで @xxx と書かれたメタデータの JSON です。