mirror of
https://github.com/coracle-social/coracle.git
synced 2024-09-19 11:43:35 +00:00
Put note kinds in a variable
This commit is contained in:
parent
4f0910e0c6
commit
61f44e340a
@ -1,8 +1,7 @@
|
|||||||
# Current
|
# Current
|
||||||
|
|
||||||
- [ ] Feeds load forever if a modal is open
|
- [ ] Feeds load forever if a modal is open
|
||||||
- [ ] Support other list types
|
- [ ] Support other list types than 30001
|
||||||
- [ ] Use vida to stream development
|
|
||||||
- [ ] Fix connection management stuff. Have GPT help
|
- [ ] Fix connection management stuff. Have GPT help
|
||||||
- [ ] Add preview proxy thing
|
- [ ] Add preview proxy thing
|
||||||
- [ ] White-labeled
|
- [ ] White-labeled
|
||||||
|
@ -1,7 +1,8 @@
|
|||||||
import {last, pick, uniqBy} from "ramda"
|
import {last, pick, uniqBy} from "ramda"
|
||||||
import {get} from "svelte/store"
|
import {get} from "svelte/store"
|
||||||
import {doPipe} from "hurdak/lib/hurdak"
|
import {doPipe} from "hurdak/lib/hurdak"
|
||||||
import {parseContent, Tags, roomAttrs, displayPerson, findRoot, findReply} from "src/util/nostr"
|
import {Tags, roomAttrs, displayPerson, findRoot, findReply} from "src/util/nostr"
|
||||||
|
import {parseContent} from "src/util/notes"
|
||||||
import {getRelayForPersonHint, getRelayForEventHint} from "src/agent/relays"
|
import {getRelayForPersonHint, getRelayForEventHint} from "src/agent/relays"
|
||||||
import {getPersonWithFallback} from "src/agent/db"
|
import {getPersonWithFallback} from "src/agent/db"
|
||||||
import pool from "src/agent/pool"
|
import pool from "src/agent/pool"
|
||||||
|
@ -6,7 +6,7 @@
|
|||||||
import {fly} from "svelte/transition"
|
import {fly} from "svelte/transition"
|
||||||
import {quantify} from "hurdak/lib/hurdak"
|
import {quantify} from "hurdak/lib/hurdak"
|
||||||
import {fuzzy, createScroller, now, timedelta} from "src/util/misc"
|
import {fuzzy, createScroller, now, timedelta} from "src/util/misc"
|
||||||
import {asDisplayEvent} from "src/util/nostr"
|
import {asDisplayEvent, noteKinds} from "src/util/nostr"
|
||||||
import Spinner from "src/partials/Spinner.svelte"
|
import Spinner from "src/partials/Spinner.svelte"
|
||||||
import Modal from "src/partials/Modal.svelte"
|
import Modal from "src/partials/Modal.svelte"
|
||||||
import Content from "src/partials/Content.svelte"
|
import Content from "src/partials/Content.svelte"
|
||||||
@ -42,7 +42,7 @@
|
|||||||
const maxNotes = 100
|
const maxNotes = 100
|
||||||
const seen = new Set()
|
const seen = new Set()
|
||||||
const getModal = () => last(document.querySelectorAll(".modal-content"))
|
const getModal = () => last(document.querySelectorAll(".modal-content"))
|
||||||
const canDisplay = e => [1, 1985].includes(e.kind)
|
const canDisplay = e => noteKinds.includes(e.kind)
|
||||||
|
|
||||||
const setFeedRelay = relay => {
|
const setFeedRelay = relay => {
|
||||||
feedRelay = relay
|
feedRelay = relay
|
||||||
|
@ -3,7 +3,8 @@
|
|||||||
import {fly} from "svelte/transition"
|
import {fly} from "svelte/transition"
|
||||||
import {splice, switcher, switcherFn} from "hurdak/lib/hurdak"
|
import {splice, switcher, switcherFn} from "hurdak/lib/hurdak"
|
||||||
import {warn} from "src/util/logger"
|
import {warn} from "src/util/logger"
|
||||||
import {displayPerson, parseContent, getLabelQuality, displayRelay, Tags} from "src/util/nostr"
|
import {displayPerson, getLabelQuality, displayRelay, Tags} from "src/util/nostr"
|
||||||
|
import {parseContent} from "src/util/notes"
|
||||||
import {modal} from "src/partials/state"
|
import {modal} from "src/partials/state"
|
||||||
import MediaSet from "src/partials/MediaSet.svelte"
|
import MediaSet from "src/partials/MediaSet.svelte"
|
||||||
import QRCode from "src/partials/QRCode.svelte"
|
import QRCode from "src/partials/QRCode.svelte"
|
||||||
@ -29,8 +30,6 @@
|
|||||||
let content = parseContent(note)
|
let content = parseContent(note)
|
||||||
let rating = note.kind === 1985 ? getLabelQuality("review/relay", note) : null
|
let rating = note.kind === 1985 ? getLabelQuality("review/relay", note) : null
|
||||||
|
|
||||||
console.log(content)
|
|
||||||
|
|
||||||
const links = []
|
const links = []
|
||||||
const invoices = []
|
const invoices = []
|
||||||
const ranges = []
|
const ranges = []
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import {ellipsize} from "hurdak/lib/hurdak"
|
import {ellipsize} from "hurdak/lib/hurdak"
|
||||||
import {displayPerson, parseContent} from "src/util/nostr"
|
import {displayPerson} from "src/util/nostr"
|
||||||
|
import {parseContent} from "src/util/notes"
|
||||||
import Anchor from "src/partials/Anchor.svelte"
|
import Anchor from "src/partials/Anchor.svelte"
|
||||||
import {getPersonWithFallback} from "src/agent/db"
|
import {getPersonWithFallback} from "src/agent/db"
|
||||||
|
|
||||||
|
@ -1,12 +1,13 @@
|
|||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import {timedelta} from "src/util/misc"
|
import {timedelta} from "src/util/misc"
|
||||||
|
import {noteKinds} from "src/util/nostr"
|
||||||
import Feed from "src/app/shared/Feed.svelte"
|
import Feed from "src/app/shared/Feed.svelte"
|
||||||
|
|
||||||
export let pubkey
|
export let pubkey
|
||||||
export let relays
|
export let relays
|
||||||
export let invertColors = false
|
export let invertColors = false
|
||||||
|
|
||||||
const filter = {kinds: [1, 1985], authors: [pubkey]}
|
const filter = {kinds: noteKinds, authors: [pubkey]}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<Feed {relays} {filter} {invertColors} parentsTimeout={3000} delta={timedelta(3, "days")} />
|
<Feed {relays} {filter} {invertColors} parentsTimeout={3000} delta={timedelta(3, "days")} />
|
||||||
|
@ -10,7 +10,7 @@ import {createMap, doPipe, first} from "hurdak/lib/hurdak"
|
|||||||
import {warn} from "src/util/logger"
|
import {warn} from "src/util/logger"
|
||||||
import {hash, shuffle, sleep, clamp} from "src/util/misc"
|
import {hash, shuffle, sleep, clamp} from "src/util/misc"
|
||||||
import {now, timedelta} from "src/util/misc"
|
import {now, timedelta} from "src/util/misc"
|
||||||
import {Tags, isNotification, userKinds} from "src/util/nostr"
|
import {Tags, isNotification, userKinds, noteKinds} from "src/util/nostr"
|
||||||
import {findReplyId} from "src/util/nostr"
|
import {findReplyId} from "src/util/nostr"
|
||||||
import {modal, toast} from "src/partials/state"
|
import {modal, toast} from "src/partials/state"
|
||||||
import {notifications, watch, userEvents, contacts, rooms} from "src/agent/db"
|
import {notifications, watch, userEvents, contacts, rooms} from "src/agent/db"
|
||||||
@ -157,7 +157,11 @@ const processChats = async (pubkey, events) => {
|
|||||||
export const listen = async () => {
|
export const listen = async () => {
|
||||||
const pubkey = user.getPubkey()
|
const pubkey = user.getPubkey()
|
||||||
const {roomsJoined} = user.getProfile()
|
const {roomsJoined} = user.getProfile()
|
||||||
const kinds = enableZaps ? [1, 4, 7, 1985, 9735] : [1, 4, 7, 1985]
|
const kinds = noteKinds.concat([4, 7])
|
||||||
|
|
||||||
|
if (enableZaps) {
|
||||||
|
kinds.push(9735)
|
||||||
|
}
|
||||||
|
|
||||||
// Only grab notifications since we last checked, with some wiggle room
|
// Only grab notifications since we last checked, with some wiggle room
|
||||||
const since =
|
const since =
|
||||||
@ -175,7 +179,7 @@ export const listen = async () => {
|
|||||||
;(listen as any)._listener = await network.listen({
|
;(listen as any)._listener = await network.listen({
|
||||||
relays: getUserReadRelays(),
|
relays: getUserReadRelays(),
|
||||||
filter: [
|
filter: [
|
||||||
{kinds: [1, 4], authors: [pubkey], since},
|
{kinds: [4], authors: [pubkey], since},
|
||||||
{kinds, "#p": [pubkey], since},
|
{kinds, "#p": [pubkey], since},
|
||||||
{kinds, "#e": eventIds, since},
|
{kinds, "#e": eventIds, since},
|
||||||
{kinds: [42], "#e": roomsJoined, since},
|
{kinds: [42], "#e": roomsJoined, since},
|
||||||
|
@ -2,7 +2,7 @@
|
|||||||
import cx from "classnames"
|
import cx from "classnames"
|
||||||
import type {DynamicFilter} from "src/util/types"
|
import type {DynamicFilter} from "src/util/types"
|
||||||
import {indexBy, objOf} from "ramda"
|
import {indexBy, objOf} from "ramda"
|
||||||
import {Tags} from "src/util/nostr"
|
import {Tags, noteKinds} from "src/util/nostr"
|
||||||
import {modal, theme} from "src/partials/state"
|
import {modal, theme} from "src/partials/state"
|
||||||
import Anchor from "src/partials/Anchor.svelte"
|
import Anchor from "src/partials/Anchor.svelte"
|
||||||
import Content from "src/partials/Content.svelte"
|
import Content from "src/partials/Content.svelte"
|
||||||
@ -16,7 +16,7 @@
|
|||||||
let relays = null
|
let relays = null
|
||||||
let key = Math.random()
|
let key = Math.random()
|
||||||
let filter = {
|
let filter = {
|
||||||
kinds: [1, 1985],
|
kinds: noteKinds,
|
||||||
authors: getUserFollows().length > 0 ? "follows" : "network",
|
authors: getUserFollows().length > 0 ? "follows" : "network",
|
||||||
} as DynamicFilter
|
} as DynamicFilter
|
||||||
|
|
||||||
|
@ -5,6 +5,7 @@ import {ensurePlural, ellipsize, first} from "hurdak/lib/hurdak"
|
|||||||
import {tryJson, avg} from "src/util/misc"
|
import {tryJson, avg} from "src/util/misc"
|
||||||
import {invoiceAmount} from "src/util/lightning"
|
import {invoiceAmount} from "src/util/lightning"
|
||||||
|
|
||||||
|
export const noteKinds = [1, 1985, 30023, 30018, 10001, 1063, 9802]
|
||||||
export const personKinds = [0, 2, 3, 10001, 10002]
|
export const personKinds = [0, 2, 3, 10001, 10002]
|
||||||
export const userKinds = personKinds.concat([10000, 30001, 30078])
|
export const userKinds = personKinds.concat([10000, 30001, 30078])
|
||||||
export const appDataKeys = [
|
export const appDataKeys = [
|
||||||
@ -191,150 +192,6 @@ export const toHex = (data: string): string | null => {
|
|||||||
export const mergeFilter = (filter, extra) =>
|
export const mergeFilter = (filter, extra) =>
|
||||||
is(Array, filter) ? filter.map(mergeLeft(extra)) : {...filter, ...extra}
|
is(Array, filter) ? filter.map(mergeLeft(extra)) : {...filter, ...extra}
|
||||||
|
|
||||||
export const parseContent = ({content, tags = []}) => {
|
|
||||||
const result = []
|
|
||||||
let text = content.trim()
|
|
||||||
let buffer = ""
|
|
||||||
|
|
||||||
const parseNewline = () => {
|
|
||||||
const newline = first(text.match(/^\n+/))
|
|
||||||
|
|
||||||
if (newline) {
|
|
||||||
return ["newline", newline, newline]
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const parseMention = () => {
|
|
||||||
// Convert legacy mentions to bech32 entities
|
|
||||||
const mentionMatch = text.match(/^#\[(\d+)\]/i)
|
|
||||||
|
|
||||||
if (mentionMatch) {
|
|
||||||
const i = parseInt(mentionMatch[1])
|
|
||||||
|
|
||||||
if (tags[i]) {
|
|
||||||
const [tag, value, url] = tags[i]
|
|
||||||
const relays = [url].filter(identity)
|
|
||||||
|
|
||||||
let type, data, entity
|
|
||||||
if (tag === "p") {
|
|
||||||
type = "nprofile"
|
|
||||||
data = {pubkey: value, relays}
|
|
||||||
entity = nip19.nprofileEncode(data)
|
|
||||||
} else {
|
|
||||||
type = "nevent"
|
|
||||||
data = {id: value, relays, pubkey: null}
|
|
||||||
entity = nip19.neventEncode(data)
|
|
||||||
}
|
|
||||||
|
|
||||||
return [`nostr:${type}`, mentionMatch[0], {...data, entity}]
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const parseTopic = () => {
|
|
||||||
const topic = first(text.match(/^#\w+/i))
|
|
||||||
|
|
||||||
// Skip numeric topics
|
|
||||||
if (topic && !topic.match(/^#\d+$/)) {
|
|
||||||
return ["topic", topic, topic.slice(1)]
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const parseBech32 = () => {
|
|
||||||
const bech32 = first(
|
|
||||||
text.match(/^(web\+)?(nostr:)?\/?\/?n(event|ote|profile|pub|addr)1[\d\w]+/i)
|
|
||||||
)
|
|
||||||
|
|
||||||
if (bech32) {
|
|
||||||
try {
|
|
||||||
const entity = fromNostrURI(bech32)
|
|
||||||
const {type, data} = nip19.decode(entity) as {type: string; data: object}
|
|
||||||
|
|
||||||
let value = data
|
|
||||||
if (type === "note") {
|
|
||||||
value = {id: data}
|
|
||||||
} else if (type === "npub") {
|
|
||||||
value = {pubkey: data}
|
|
||||||
}
|
|
||||||
|
|
||||||
return [`nostr:${type}`, bech32, {...value, entity}]
|
|
||||||
} catch (e) {
|
|
||||||
console.log(e)
|
|
||||||
// pass
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const parseLNUrl = () => {
|
|
||||||
const lnurl = first(text.match(/^ln(bc|url)[\d\w]{50,1000}/i))
|
|
||||||
|
|
||||||
if (lnurl) {
|
|
||||||
return ["lnurl", lnurl, lnurl]
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const parseUrl = () => {
|
|
||||||
const raw = first(text.match(/^([a-z\+:]{2,30}:\/\/)?[^\s]+\.[a-z]{2,6}[^\s]*[^\.!?,:\s]/gi))
|
|
||||||
|
|
||||||
// Skip url if it's just the end of a filepath
|
|
||||||
if (raw) {
|
|
||||||
const prev = last(result)
|
|
||||||
|
|
||||||
if (prev?.type === "text" && prev.value.endsWith("/")) {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
let url = raw
|
|
||||||
|
|
||||||
// Skip ellipses and very short non-urls
|
|
||||||
if (url.match(/\.\./)) {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!url.match("://")) {
|
|
||||||
url = "https://" + url
|
|
||||||
}
|
|
||||||
|
|
||||||
return ["link", raw, url]
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
while (text) {
|
|
||||||
const part =
|
|
||||||
parseNewline() ||
|
|
||||||
parseMention() ||
|
|
||||||
parseTopic() ||
|
|
||||||
parseBech32() ||
|
|
||||||
parseUrl() ||
|
|
||||||
parseLNUrl()
|
|
||||||
|
|
||||||
if (part) {
|
|
||||||
if (buffer) {
|
|
||||||
result.push({type: "text", value: buffer})
|
|
||||||
buffer = ""
|
|
||||||
}
|
|
||||||
|
|
||||||
const [type, raw, value] = part
|
|
||||||
|
|
||||||
result.push({type, value})
|
|
||||||
text = text.slice(raw.length)
|
|
||||||
} else {
|
|
||||||
// Instead of going character by character and re-running all the above regular expressions
|
|
||||||
// a million times, try to match the next word and add it to the buffer
|
|
||||||
const match = first(text.match(/^[\w\d]+ ?/i)) || text[0]
|
|
||||||
|
|
||||||
buffer += match
|
|
||||||
text = text.slice(match.length)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (buffer) {
|
|
||||||
result.push({type: "text", value: buffer})
|
|
||||||
}
|
|
||||||
|
|
||||||
return result
|
|
||||||
}
|
|
||||||
|
|
||||||
export const processZaps = (zaps, author) =>
|
export const processZaps = (zaps, author) =>
|
||||||
zaps
|
zaps
|
||||||
.map(zap => {
|
.map(zap => {
|
||||||
|
148
src/util/notes.ts
Normal file
148
src/util/notes.ts
Normal file
@ -0,0 +1,148 @@
|
|||||||
|
import {last, identity} from "ramda"
|
||||||
|
import {nip19} from "nostr-tools"
|
||||||
|
import {first} from "hurdak/lib/hurdak"
|
||||||
|
import {fromNostrURI} from "src/util/nostr"
|
||||||
|
|
||||||
|
export const parseContent = ({content, tags = []}) => {
|
||||||
|
const result = []
|
||||||
|
let text = content.trim()
|
||||||
|
let buffer = ""
|
||||||
|
|
||||||
|
const parseNewline = () => {
|
||||||
|
const newline = first(text.match(/^\n+/))
|
||||||
|
|
||||||
|
if (newline) {
|
||||||
|
return ["newline", newline, newline]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const parseMention = () => {
|
||||||
|
// Convert legacy mentions to bech32 entities
|
||||||
|
const mentionMatch = text.match(/^#\[(\d+)\]/i)
|
||||||
|
|
||||||
|
if (mentionMatch) {
|
||||||
|
const i = parseInt(mentionMatch[1])
|
||||||
|
|
||||||
|
if (tags[i]) {
|
||||||
|
const [tag, value, url] = tags[i]
|
||||||
|
const relays = [url].filter(identity)
|
||||||
|
|
||||||
|
let type, data, entity
|
||||||
|
if (tag === "p") {
|
||||||
|
type = "nprofile"
|
||||||
|
data = {pubkey: value, relays}
|
||||||
|
entity = nip19.nprofileEncode(data)
|
||||||
|
} else {
|
||||||
|
type = "nevent"
|
||||||
|
data = {id: value, relays, pubkey: null}
|
||||||
|
entity = nip19.neventEncode(data)
|
||||||
|
}
|
||||||
|
|
||||||
|
return [`nostr:${type}`, mentionMatch[0], {...data, entity}]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const parseTopic = () => {
|
||||||
|
const topic = first(text.match(/^#\w+/i))
|
||||||
|
|
||||||
|
// Skip numeric topics
|
||||||
|
if (topic && !topic.match(/^#\d+$/)) {
|
||||||
|
return ["topic", topic, topic.slice(1)]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const parseBech32 = () => {
|
||||||
|
const bech32 = first(
|
||||||
|
text.match(/^(web\+)?(nostr:)?\/?\/?n(event|ote|profile|pub|addr)1[\d\w]+/i)
|
||||||
|
)
|
||||||
|
|
||||||
|
if (bech32) {
|
||||||
|
try {
|
||||||
|
const entity = fromNostrURI(bech32)
|
||||||
|
const {type, data} = nip19.decode(entity) as {type: string; data: object}
|
||||||
|
|
||||||
|
let value = data
|
||||||
|
if (type === "note") {
|
||||||
|
value = {id: data}
|
||||||
|
} else if (type === "npub") {
|
||||||
|
value = {pubkey: data}
|
||||||
|
}
|
||||||
|
|
||||||
|
return [`nostr:${type}`, bech32, {...value, entity}]
|
||||||
|
} catch (e) {
|
||||||
|
console.log(e)
|
||||||
|
// pass
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const parseLNUrl = () => {
|
||||||
|
const lnurl = first(text.match(/^ln(bc|url)[\d\w]{50,1000}/i))
|
||||||
|
|
||||||
|
if (lnurl) {
|
||||||
|
return ["lnurl", lnurl, lnurl]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const parseUrl = () => {
|
||||||
|
const raw = first(text.match(/^([a-z\+:]{2,30}:\/\/)?[^\s]+\.[a-z]{2,6}[^\s]*[^\.!?,:\s]/gi))
|
||||||
|
|
||||||
|
// Skip url if it's just the end of a filepath
|
||||||
|
if (raw) {
|
||||||
|
const prev = last(result)
|
||||||
|
|
||||||
|
if (prev?.type === "text" && prev.value.endsWith("/")) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
let url = raw
|
||||||
|
|
||||||
|
// Skip ellipses and very short non-urls
|
||||||
|
if (url.match(/\.\./)) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!url.match("://")) {
|
||||||
|
url = "https://" + url
|
||||||
|
}
|
||||||
|
|
||||||
|
return ["link", raw, url]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
while (text) {
|
||||||
|
const part =
|
||||||
|
parseNewline() ||
|
||||||
|
parseMention() ||
|
||||||
|
parseTopic() ||
|
||||||
|
parseBech32() ||
|
||||||
|
parseUrl() ||
|
||||||
|
parseLNUrl()
|
||||||
|
|
||||||
|
if (part) {
|
||||||
|
if (buffer) {
|
||||||
|
result.push({type: "text", value: buffer})
|
||||||
|
buffer = ""
|
||||||
|
}
|
||||||
|
|
||||||
|
const [type, raw, value] = part
|
||||||
|
|
||||||
|
result.push({type, value})
|
||||||
|
text = text.slice(raw.length)
|
||||||
|
} else {
|
||||||
|
// Instead of going character by character and re-running all the above regular expressions
|
||||||
|
// a million times, try to match the next word and add it to the buffer
|
||||||
|
const match = first(text.match(/^[\w\d]+ ?/i)) || text[0]
|
||||||
|
|
||||||
|
buffer += match
|
||||||
|
text = text.slice(match.length)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (buffer) {
|
||||||
|
result.push({type: "text", value: buffer})
|
||||||
|
}
|
||||||
|
|
||||||
|
return result
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user