Add cross-posting

This commit is contained in:
Jon Staab 2023-11-21 08:52:28 -08:00
parent 5e3c919245
commit 54d738aefa
5 changed files with 131 additions and 45 deletions

1
.env
View File

@ -4,6 +4,7 @@ VITE_DEFAULT_RELAYS=wss://purplepag.es,wss://relay.damus.io,wss://relay.nostr.ba
VITE_DEFAULT_FOLLOWS=1739d937dc8c0c7370aa27585938c119e25c41f6c441a5d34c6d38503e3136ef,fa984bd7dbb282f07e16e7ae87b26a2a7b9b90b7246a44771f0cf5ae58018f52,cc8d072efdcc676fcbac14f6cd6825edc3576e55eb786a2a975ee034a6a026cb,d91191e30e00444b942c0e82cad470b32af171764c2275bee0bd99377efd4075,3335d373e6c1b5bc669b4b1220c08728ea8ce622e5a7cfeeb4c0001d91ded1de,0b118e40d6f3dfabb17f21a94a647701f140d8b063a9e84fe6e483644edc09cb,b83a28b7e4e5d20bd960c5faeb6625f95529166b8bdb045d42634a2f35919450,958b754a1d3de5b5eca0fe31d2d555f451325f8498a83da1997b7fcd5c39e88c,b9e76546ba06456ed301d9e52bc49fa48e70a6bf2282be7a1ae72947612023dc,b708f7392f588406212c3882e7b3bc0d9b08d62f95fa170d099127ece2770e5e,5c508c34f58866ec7341aaf10cc1af52e9232bb9f859c8103ca5ecf2aa93bf78,baf27a4cc4da49913e7fdecc951fd3b971c9279959af62b02b761a043c33384c,2edbcea694d164629854a52583458fd6d965b161e3c48b57d3aff01940558884,0fecf65daa26faf3f668e8143325a4c199a040b6345ed40a08614d7dd85b1823,1bc70a0148b3f316da33fe3c89f23e3e71ac4ff998027ec712b905cd24f6a411,f783ba3b12b91e375aba6594015b90bd95f7e132b03cc8c4c52ce0a7c36aab52,3f770d65d3a764a9c5cb503ae123e62ec7598ad035d836e2a810f3877a745b24,82341f882b6eabcd2ba7f1ef90aad961cf074af15b9ef44a09f9d2a8fbfbe6a2,3bf0c63fcb93463407af97a5e5ee64fa883d107ef9e558472c4eb9aaaefa459d,ee11a5dff40c19a555f41fe42b48f00e618c91225622ae37b6c2bb67b76c4e49,97c70a44366a6535c145b333f973ea86dfdc2d7a99da618c40c64705ad98e322,a1fc5dfd7ffcf563c89155b466751b580d115e136e2f8c90e8913385bbedb1cf,84dee6e676e5bb67b4ad4e042cf70cbd8681155db535942fcc6a0533858a7240
VITE_IMGPROXY_URL=https://imgproxy.coracle.social
VITE_DUFFLEPUD_URL=https://dufflepud.onrender.com
VITE_ENABLE_GROUPS=true
VITE_ENABLE_ZAPS=true
VITE_FORCE_RELAYS=
VITE_LOGO_URL=

View File

@ -154,6 +154,9 @@
zapper
)
// Split out reposts
$: reposts = children.filter(e => [6, 16].includes(e.kind))
onMount(async () => {
const zapAddress = Tags.from(note).getValue("zap")
@ -191,6 +194,11 @@
kinds.push(9735)
}
if ($env.ENABLE_GROUPS && !event.wrap) {
kinds.push(6)
kinds.push(16)
}
load({
relays: mergeHints([relays, getReplyHints(event)]),
filters: getReplyFilters([event], {kinds}),

View File

@ -3,12 +3,20 @@
import {nip19} from "nostr-tools"
import {toNostrURI, createEvent} from "paravel"
import {tweened} from "svelte/motion"
import {identity, sum, pluck, sortBy} from "ramda"
import {identity, sum, uniqBy, prop, pluck, sortBy} from "ramda"
import {formatSats} from "src/util/misc"
import {LOCAL_RELAY_URL, getGroupAddress, asNostrEvent, getIdOrAddress} from "src/util/nostr"
import {
LOCAL_RELAY_URL,
getGroupAddress,
getIdOrAddressTag,
asNostrEvent,
getIdOrAddress,
} from "src/util/nostr"
import {quantify} from "hurdak"
import {toast} from "src/partials/state"
import Popover from "src/partials/Popover.svelte"
import Card from "src/partials/Card.svelte"
import Heading from "src/partials/Heading.svelte"
import ColorDot from "src/partials/ColorDot.svelte"
import Content from "src/partials/Content.svelte"
import Modal from "src/partials/Modal.svelte"
@ -16,15 +24,18 @@
import CopyValue from "src/partials/CopyValue.svelte"
import PersonBadge from "src/app/shared/PersonBadge.svelte"
import RelayCard from "src/app/shared/RelayCard.svelte"
import GroupSummary from "src/app/shared/GroupSummary.svelte"
import {router} from "src/app/router"
import type {Event} from "src/engine"
import {
env,
mute,
unmute,
groups,
canSign,
session,
Publisher,
mention,
signer,
deriveGroupAccess,
publishToZeroOrMoreGroups,
@ -44,11 +55,10 @@
export let showMuted
export let showEntire
export let removeFromContext
export let replies
export let likes
export let zaps
export let replies, likes, zaps
export let zapper
const address = getGroupAddress(note)
const relays = getEventHints(note)
const nevent = nip19.neventEncode({id: note.id, relays})
const muted = isEventMuted.derived($isEventMuted => $isEventMuted(note, true))
@ -59,6 +69,10 @@
//const report = () => router.at("notes").of(note.id, {relays: getEventHints(note)}).at('report').qp({pubkey: note.pubkey}).open()
const setView = v => {
view = v
}
const label = () => router.at("notes").of(note.id, {relays}).at("label").open()
const quote = () => router.at("notes/create").cx({quote: note, relays}).open()
@ -87,6 +101,24 @@
removeFromContext(e)
}
const crossPost = async address => {
const relays = getPublishHints(note)
const tags = [getIdOrAddressTag(note, relays[0]), mention(note.pubkey)]
const content = JSON.stringify(asNostrEvent(note))
const shouldWrap = groups.key(address).get()?.access === "closed"
let template
if (note.kind === 1) {
template = createEvent(6, {content, tags})
} else {
template = createEvent(16, {content, tags: [...tags, ["k", note.kind]]})
}
publishToZeroOrMoreGroups([address], template, {relays, shouldWrap})
setView(null)
}
const startZap = () =>
router
.at("people")
@ -110,11 +142,24 @@
.cx({relays: [url]})
.open()
let like, allLikes, zap
let showDetails = false
const groupOptions = session.derived($session => {
const options = []
for (const addr of Object.keys($session.groups || {})) {
const group = groups.key(addr).get()
const access = deriveGroupAccess(addr).get()
if (group && access === "granted" && addr !== address) {
options.push(group)
}
}
return uniqBy(prop("address"), options)
})
let view
let actions = []
$: address = getGroupAddress(note)
$: disableActions =
!$canSign ||
($muted && !showMuted) ||
@ -140,6 +185,7 @@
actions = []
actions.push({label: "Quote", icon: "quote-left", onClick: quote})
actions.push({label: "Cross-post", icon: "shuffle", onClick: () => setView('cross-post')})
actions.push({label: "Tag", icon: "tag", onClick: label})
//actions.push({label: "Report", icon: "triangle-exclamation", onClick: report})
@ -156,9 +202,7 @@
actions.push({
label: "Details",
icon: "info",
onClick: () => {
showDetails = true
},
onClick: () => setView("info"),
})
}
</script>
@ -243,43 +287,67 @@
</div>
</div>
{#if showDetails}
<Modal
onEscape={() => {
showDetails = false
}}>
{#if view}
<Modal onEscape={() => setView(null)}>
<Content>
{#if zaps.length > 0}
<h1 class="staatliches text-2xl">Zapped By</h1>
<div class="grid grid-cols-2 gap-2">
{#each zaps as zap}
<div class="flex flex-col gap-1">
<PersonBadge pubkey={zap.request.pubkey} />
<span class="ml-16 text-sm text-gray-5"
>{formatSats(zap.invoiceAmount / 1000)} sats</span>
{#if view === "info"}
{#if zaps.length > 0}
<h1 class="staatliches text-2xl">Zapped By</h1>
<div class="grid grid-cols-2 gap-2">
{#each zaps as zap}
<div class="flex flex-col gap-1">
<PersonBadge pubkey={zap.request.pubkey} />
<span class="ml-16 text-sm text-gray-5"
>{formatSats(zap.invoiceAmount / 1000)} sats</span>
</div>
{/each}
</div>
{/if}
{#if likes.length > 0}
<h1 class="staatliches text-2xl">Liked By</h1>
<div class="grid grid-cols-2 gap-2">
{#each likes as like}
<PersonBadge pubkey={like.pubkey} />
{/each}
</div>
{/if}
{#if note.seen_on.length > 0}
<h1 class="staatliches text-2xl">Relays</h1>
<p>This note was found on {quantify(note.seen_on.length, "relay")} below.</p>
<div class="flex flex-col gap-2">
{#each note.seen_on as url}
<RelayCard relay={{url}} />
{/each}
</div>
{/if}
<h1 class="staatliches text-2xl">Details</h1>
<CopyValue label="Link" value={toNostrURI(nevent)} />
<CopyValue label="Event ID" encode={nip19.noteEncode} value={note.id} />
<CopyValue label="Event JSON" value={JSON.stringify(asNostrEvent(note))} />
{:else if view === "cross-post"}
<div class="mb-4 flex items-center justify-center">
<Heading>Cross-post</Heading>
</div>
<div>Select where you'd like to post to:</div>
<div class="flex flex-col gap-2">
{#if address}
<Card invertColors interactive on:click={() => crossPost()}>
<div class="flex gap-4 text-gray-1">
<i class="fa fa-earth-asia fa-2x" />
<div class="flex min-w-0 flex-grow flex-col gap-4">
<p class="text-2xl">Global</p>
<p>Post to your main feed.</p>
</div>
</div>
</Card>
{/if}
{#each $groupOptions as g (g.address)}
<Card invertColors interactive on:click={() => crossPost(g.address)}>
<GroupSummary address={g.address} />
</Card>
{/each}
</div>
{/if}
{#if likes.length > 0}
<h1 class="staatliches text-2xl">Liked By</h1>
<div class="grid grid-cols-2 gap-2">
{#each likes as like}
<PersonBadge pubkey={like.pubkey} />
{/each}
</div>
{/if}
<h1 class="staatliches text-2xl">Relays</h1>
<p>This note was found on {quantify(note.seen_on.length, "relay")} below.</p>
<div class="flex flex-col gap-2">
{#each note.seen_on as url}
<RelayCard relay={{url}} />
{/each}
</div>
<h1 class="staatliches text-2xl">Details</h1>
<CopyValue label="Link" value={toNostrURI(nevent)} />
<CopyValue label="Event ID" encode={nip19.noteEncode} value={note.id} />
<CopyValue label="Event JSON" value={JSON.stringify(asNostrEvent(note))} />
</Content>
</Modal>
{/if}

View File

@ -46,8 +46,7 @@ const MULTIPLEXTR_URL = import.meta.env.VITE_MULTIPLEXTR_URL
const FORCE_RELAYS = fromCsv(import.meta.env.VITE_FORCE_RELAYS)
const DVM_RELAYS =
FORCE_RELAYS.length > 0 ? FORCE_RELAYS : fromCsv(import.meta.env.VITE_DVM_RELAYS)
const DVM_RELAYS = FORCE_RELAYS.length > 0 ? FORCE_RELAYS : fromCsv(import.meta.env.VITE_DVM_RELAYS)
const SEARCH_RELAYS =
FORCE_RELAYS.length > 0 ? FORCE_RELAYS : ["wss://relay.nostr.band", "wss://nostr.wine"]
@ -59,6 +58,8 @@ const DEFAULT_FOLLOWS = fromCsv(import.meta.env.VITE_DEFAULT_FOLLOWS)
const ENABLE_ZAPS = JSON.parse(import.meta.env.VITE_ENABLE_ZAPS)
const ENABLE_GROUPS = JSON.parse(import.meta.env.VITE_ENABLE_GROUPS)
// Prep our env
env.set({
DEFAULT_FOLLOWS,
@ -70,6 +71,7 @@ env.set({
SEARCH_RELAYS,
DEFAULT_RELAYS,
ENABLE_ZAPS,
ENABLE_GROUPS,
})
// Throw some hardcoded defaults in there

View File

@ -62,6 +62,13 @@ export const getIdOrAddress = e => {
return e.id
}
export const getIdOrAddressTag = (e, hint) => {
const value = getIdOrAddress(e)
const type = value.includes(":") ? "a" : "e"
return [type, value, hint]
}
export const getGroupAddress = e =>
Tags.from(e)
.type("a")