diff --git a/components/PlaylistFeed/PlaylistFeed.tsx b/components/PlaylistFeed/PlaylistFeed.tsx new file mode 100644 index 0000000..f9364a4 --- /dev/null +++ b/components/PlaylistFeed/PlaylistFeed.tsx @@ -0,0 +1,79 @@ +import { useEffect, useState } from "react"; +import { type NDKEvent } from "@nostr-dev-kit/ndk"; +import { useNDK } from "../../ndk/NDKProvider"; +import { EventProvider } from "../../ndk/NDKEventProvider"; +import { FeedNote } from "../Note/Note"; +import { Stack } from "@mantine/core"; +import useFooterHeight from "../../ndk/hooks/useFooterHeight"; + +export default function PlaylistFeed({ + d, + playlistCreatorPubkey, +}: { + d: string; + playlistCreatorPubkey: string; +}) { + const { ndk, stemstrRelaySet } = useNDK(); + const [events, setEvents] = useState([]); + const footerHeight = useFooterHeight(); + + useEffect(() => { + if (!ndk) { + return; + } + + ndk + .fetchEvent( + { + kinds: [30001], + authors: [playlistCreatorPubkey], + "#d": [d], + }, + {} + ) + .then((event) => { + if (event) { + return event.getMatchingTags("e").map((tag) => tag[1]); + } + }) + .then(async (eventIds) => { + if (eventIds) { + return { + sortedEventIds: eventIds, + events: await ndk.fetchEvents( + { ids: eventIds }, + {}, + stemstrRelaySet + ), + }; + } + + return { sortedEventIds: [], events: [] }; + }) + .then(({ sortedEventIds, events }) => { + if (!events) { + return; + } + + const eventsMap: Record = {}; + + events.forEach((event) => { + eventsMap[event.id] = event; + }); + + setEvents(sortedEventIds.map((id) => eventsMap[id])); + }) + .catch(console.error); + }, [d, ndk, stemstrRelaySet, playlistCreatorPubkey]); + + // Not using the Feed component because it causes an infinite loop for some reason + return ( + + {events.map((event) => ( + + + + ))} + + ); +} diff --git a/package.json b/package.json index e52d445..479615e 100644 --- a/package.json +++ b/package.json @@ -51,7 +51,7 @@ "next": "13.1.6", "next-pwa": "^5.6.0", "next-redux-wrapper": "^8.1.0", - "nostr-tools": "^1.6.0", + "nostr-tools": "1.10.1", "qrcode.react": "^3.1.0", "react": "18.2.0", "react-device-detect": "^2.2.3", diff --git a/pages/playlist/[naddr].tsx b/pages/playlist/[naddr].tsx new file mode 100644 index 0000000..1b9c04a --- /dev/null +++ b/pages/playlist/[naddr].tsx @@ -0,0 +1,57 @@ +import { Flex, Stack, Text } from "@mantine/core"; +import Head from "next/head"; +import FeedHeader from "components/FeedHeader/FeedHeader"; +import { useRouter } from "next/router"; +import { nip19 } from "nostr-tools"; +import { Route } from "../../enums"; +import { ChevronLeftIcon } from "../../icons/StemstrIcon"; +import BackButton from "../../components/BackButton/BackButton"; +import PlaylistFeed from "../../components/PlaylistFeed/PlaylistFeed"; + +const useNip19Address = () => { + const router = useRouter(); + const { naddr } = router.query; + + try { + const { type, data } = nip19.decode(naddr as string); + + if (type === "naddr") { + return data as nip19.AddressPointer; + } + } catch (error) { + console.error(error); + } +}; + +export default function Playlist() { + // the address id should be a slug, but listr.lol uses the title as the id so just going with using the id as the + // title for now + const { identifier: playlistTitle, pubkey } = useNip19Address() ?? {}; + + if (!playlistTitle || !pubkey) { + return null; + } + + return ( + <> + + Stemstr - {playlistTitle} + + + + + + + + {playlistTitle} + + + + + + ); +} diff --git a/yarn.lock b/yarn.lock index 95cd695..cdba9d7 100644 --- a/yarn.lock +++ b/yarn.lock @@ -3868,10 +3868,10 @@ dependencies: "@noble/hashes" "1.3.0" -"@noble/hashes@1.0.0": - version "1.0.0" - resolved "https://registry.yarnpkg.com/@noble/hashes/-/hashes-1.0.0.tgz#d5e38bfbdaba174805a4e649f13be9a9ed3351ae" - integrity sha512-DZVbtY62kc3kkBtMHqwCOfXrT/hnoORy5BJ4+HU1IR59X0KWAOqsfzQPcUl/lQLlG7qXbe/fZ3r/emxtAl+sqg== +"@noble/hashes@1.2.0", "@noble/hashes@~1.2.0": + version "1.2.0" + resolved "https://registry.yarnpkg.com/@noble/hashes/-/hashes-1.2.0.tgz#a3150eeb09cc7ab207ebf6d7b9ad311a9bdbed12" + integrity sha512-FZfhjEDbT5GRswV3C6uvLPHMiVD6lQBmpoX5+eSiPaMTXte/IKqI5dykDxzZB/WBeK/CDuQRBWarPdi3FNY2zQ== "@noble/hashes@1.3.0", "@noble/hashes@~1.3.0": version "1.3.0" @@ -3883,14 +3883,9 @@ resolved "https://registry.yarnpkg.com/@noble/hashes/-/hashes-1.3.1.tgz#8831ef002114670c603c458ab8b11328406953a9" integrity sha512-EbqwksQwz9xDRGfDST86whPBgM65E0OH/pCgqW0GBVzO22bNE+NuIbeTb714+IfSjU3aRk47EUvXIb5bTsenKA== -"@noble/hashes@~1.2.0": - version "1.2.0" - resolved "https://registry.npmjs.org/@noble/hashes/-/hashes-1.2.0.tgz" - integrity sha512-FZfhjEDbT5GRswV3C6uvLPHMiVD6lQBmpoX5+eSiPaMTXte/IKqI5dykDxzZB/WBeK/CDuQRBWarPdi3FNY2zQ== - -"@noble/secp256k1@^1.7.1", "@noble/secp256k1@~1.7.0": +"@noble/secp256k1@1.7.1", "@noble/secp256k1@~1.7.0": version "1.7.1" - resolved "https://registry.npmjs.org/@noble/secp256k1/-/secp256k1-1.7.1.tgz" + resolved "https://registry.yarnpkg.com/@noble/secp256k1/-/secp256k1-1.7.1.tgz#b251c70f824ce3ca7f8dc3df08d58f005cc0507c" integrity sha512-hOUk6AyBFmqVrv7k5WAw/LpszxVbj9gGN4JRkIX52fdFAj1UA61KXmZDvqVEm+pOyec3+fIeZB02LYa/pWOArw== "@noble/secp256k1@^2.0.0": @@ -4163,6 +4158,15 @@ resolved "https://registry.npmjs.org/@scure/base/-/base-1.1.1.tgz" integrity sha512-ZxOhsSyxYwLJj3pLZCefNitxsj093tb2vq90mp2txoYeBqbcjDjqFhyM8eUjq/uFm6zJ+mUuqxlS2FkuSY1MTA== +"@scure/bip32@1.1.4": + version "1.1.4" + resolved "https://registry.yarnpkg.com/@scure/bip32/-/bip32-1.1.4.tgz#2c91a7be0156b15f26dd0c843a06a1917f129efd" + integrity sha512-m925ACYK0wPELsF7Z/VdLGmKj1StIeHraPMYB9xiAFiq/PnvqWd/99I0TQ2OZhjjlMDsDJeZlyXMWi0beaA7NA== + dependencies: + "@noble/hashes" "~1.2.0" + "@noble/secp256k1" "~1.7.0" + "@scure/base" "~1.1.0" + "@scure/bip32@1.3.0": version "1.3.0" resolved "https://registry.yarnpkg.com/@scure/bip32/-/bip32-1.3.0.tgz#6c8d980ef3f290987736acd0ee2e0f0d50068d87" @@ -4172,13 +4176,12 @@ "@noble/hashes" "~1.3.0" "@scure/base" "~1.1.0" -"@scure/bip32@^1.1.5": - version "1.1.5" - resolved "https://registry.npmjs.org/@scure/bip32/-/bip32-1.1.5.tgz" - integrity sha512-XyNh1rB0SkEqd3tXcXMi+Xe1fvg+kUIcoRIEujP1Jgv7DqW2r9lg3Ah0NkFaCs9sTkQAQA8kw7xiRXzENi9Rtw== +"@scure/bip39@1.1.1": + version "1.1.1" + resolved "https://registry.yarnpkg.com/@scure/bip39/-/bip39-1.1.1.tgz#b54557b2e86214319405db819c4b6a370cf340c5" + integrity sha512-t+wDck2rVkh65Hmv280fYdVdY25J9YeEUIgn2LG1WM6gxFkGzcksoDiUkWVpVp3Oex9xGC68JU2dSbUfwZ2jPg== dependencies: "@noble/hashes" "~1.2.0" - "@noble/secp256k1" "~1.7.0" "@scure/base" "~1.1.0" "@scure/bip39@1.2.0": @@ -4189,14 +4192,6 @@ "@noble/hashes" "~1.3.0" "@scure/base" "~1.1.0" -"@scure/bip39@^1.1.1": - version "1.1.1" - resolved "https://registry.npmjs.org/@scure/bip39/-/bip39-1.1.1.tgz" - integrity sha512-t+wDck2rVkh65Hmv280fYdVdY25J9YeEUIgn2LG1WM6gxFkGzcksoDiUkWVpVp3Oex9xGC68JU2dSbUfwZ2jPg== - dependencies: - "@noble/hashes" "~1.2.0" - "@scure/base" "~1.1.0" - "@sinclair/typebox@^0.25.16": version "0.25.24" resolved "https://registry.yarnpkg.com/@sinclair/typebox/-/typebox-0.25.24.tgz#8c7688559979f7079aacaf31aa881c3aa410b718" @@ -12926,6 +12921,17 @@ normalize-range@^0.1.2: resolved "https://registry.npmjs.org/normalize-range/-/normalize-range-0.1.2.tgz" integrity sha1-LRDAa9/TEuqXd2laTShDlFa3WUI= +nostr-tools@1.10.1: + version "1.10.1" + resolved "https://registry.yarnpkg.com/nostr-tools/-/nostr-tools-1.10.1.tgz#b52043b3031f4314478d0a3bfaa8ffb9cc4f98a0" + integrity sha512-zgTYJeuZQ3CDASsmBEcB5i6V6l0IaA6cjnll6OVik3FoZcvbCaL7yP8I40hYnOIi3KlJykV7jEF9fn8h1NzMnA== + dependencies: + "@noble/hashes" "1.2.0" + "@noble/secp256k1" "1.7.1" + "@scure/base" "1.1.1" + "@scure/bip32" "1.1.4" + "@scure/bip39" "1.1.1" + nostr-tools@^1.11.2: version "1.12.1" resolved "https://registry.yarnpkg.com/nostr-tools/-/nostr-tools-1.12.1.tgz#4ac9c0d1cff8c7107b0d3ef647571137c2250557" @@ -12937,18 +12943,6 @@ nostr-tools@^1.11.2: "@scure/bip32" "1.3.0" "@scure/bip39" "1.2.0" -nostr-tools@^1.6.0: - version "1.6.0" - resolved "https://registry.yarnpkg.com/nostr-tools/-/nostr-tools-1.6.0.tgz#4052fe717a378982c8ce56d39986089abacfc6d3" - integrity sha512-qjjJQ7YxJUMzgS24eVlxkZ87PKJtU6dlH04OzVuK6w+GSPL+VdUZkMe2lfSpnb7OkCrDIzmbFbtx+Q4LXdU2xw== - dependencies: - "@noble/hashes" "1.0.0" - "@noble/secp256k1" "^1.7.1" - "@scure/base" "^1.1.1" - "@scure/bip32" "^1.1.5" - "@scure/bip39" "^1.1.1" - prettier "^2.8.4" - npm-run-all@^4.1.5: version "4.1.5" resolved "https://registry.yarnpkg.com/npm-run-all/-/npm-run-all-4.1.5.tgz#04476202a15ee0e2e214080861bff12a51d98fba" @@ -13774,11 +13768,6 @@ prettier@^2.7.1: resolved "https://registry.npmjs.org/prettier/-/prettier-2.7.1.tgz" integrity sha512-ujppO+MkdPqoVINuDFDRLClm7D78qbDt0/NR+wp5FqEZOoTNAjPHWj17QRhu7geIHJfcNhRk1XVQmF8Bp3ye+g== -prettier@^2.8.4: - version "2.8.4" - resolved "https://registry.yarnpkg.com/prettier/-/prettier-2.8.4.tgz#34dd2595629bfbb79d344ac4a91ff948694463c3" - integrity sha512-vIS4Rlc2FNh0BySk3Wkd6xmwxB0FpOndW5fisM5H8hsZSxU2VWVB5CWIkIjWvrHjIhxk2g3bfMKM87zNTrZddw== - pretty-bytes@^5.3.0, pretty-bytes@^5.4.1: version "5.6.0" resolved "https://registry.yarnpkg.com/pretty-bytes/-/pretty-bytes-5.6.0.tgz#356256f643804773c82f64723fe78c92c62beaeb"