nc-event
v0.0.23
Published
Lightweight Nostr event component with smart media detection. Zero dependencies, ~3KB gzipped.
Downloads
258
Readme
Why nc-event?
Smart, automatic media rendering for Nostr events. Drop in a component and watch URLs transform into embedded images, videos, YouTube players, and more.
https://example.com/photo.png → 🖼️ Rendered image
https://youtu.be/dQw4w9WgXcQ → ▶️ Embedded YouTube player
https://example.com/song.mp3 → 🎵 Audio playerFeatures
- Zero dependencies — Uses bundled Preact (~3KB), nothing to install
- Smart media detection — Recognizes 30+ file formats + YouTube, Spotify, Vimeo, and more
- Works everywhere — ES modules, no build step required
- Tested — 88 unit tests covering edge cases
- Lightweight — ~3KB gzipped total
Quick Start
Option 1: HTML Custom Element (Easiest)
Just include the script and use <nc-event> directly:
<script type="module" src="https://unpkg.com/nc-event/lib/nc-event.js"></script>
<nc-event content="Check this out! https://nostr.build/i/abc123.webp"></nc-event>With all attributes:
<nc-event
content="Hello Nostr! https://example.com/photo.png"
pubkey="82341f882b6eabcd2ba7f1ef90aad961cf074af15b9ef44a09f9d2a8fbfbe6a2"
kind="1"
></nc-event>Option 2: NPM + JavaScript
npm install nc-eventimport 'nc-event/lib/nc-event.js'
// Now <nc-event> works in your HTMLOr use the Preact component directly:
import { html, render } from 'nc-event/js/standalone.module.js'
import Event from 'nc-event'
render(html`<${Event} event=${{ content: "Hello!", kind: 1 }} />`, document.body)Option 3: Parse M3U Playlists
import { parseM3U, fetchM3U } from 'nc-event/lib/m3u-parser.js'
// Parse M3U content
const tracks = parseM3U(`#EXTM3U
#EXTINF:180,Artist - Song Title
https://example.com/song.mp3`)
// [{ url: '...', title: 'Song Title', artist: 'Artist', duration: 180, type: 'audio' }]
// Or fetch and parse from URL
const playlist = await fetchM3U('https://example.com/playlist.m3u')See the Playlist Showcase for a live demo.
Option 4: Media Detection Only
The media detection module works independently — use it in any project:
import { parseMedia, isImage, detectPlatform } from 'nc-event/lib/media.js'
// Parse all media from text
const media = parseMedia('Check https://x.com/a.png and https://youtu.be/abc123XYZ_A')
// → [
// { url: 'https://x.com/a.png', type: 'image' },
// { url: 'https://youtu.be/abc123XYZ_A', type: 'video', platform: 'youtube', id: 'abc123XYZ_A' }
// ]
// Simple type checks
isImage('https://example.com/photo.webp') // true
isImage('https://example.com/video.mp4') // false
// Detect embeddable platforms
detectPlatform('https://youtube.com/watch?v=dQw4w9WgXcQ')
// → { platform: 'youtube', type: 'video', id: 'dQw4w9WgXcQ' }Live Examples
Try these in your browser:
| Example | Description | |---------|-------------| | Single Image | Basic image rendering | | Multiple Images | Gallery of images | | Video | Native video player | | YouTube | Embedded YouTube | | Kind 1 Event | Full event with metadata | | M3U Playlist | Parsed playlist showcase |
API
<nc-event> Custom Element
The easiest way to use nc-event. Just add attributes:
<nc-event content="Hello! https://example.com/photo.png" pubkey="82341f..." kind="1"></nc-event>Attributes:
| Attribute | Type | Description |
|-----------|------|-------------|
| content | string | Event content with URLs to detect |
| pubkey | string | Author's public key (optional) |
| kind | number | Event kind, default 1 |
| id | string | Event ID (optional) |
| created-at | number | Unix timestamp (optional) |
<Event> Preact Component
For more control, use the Preact component directly:
import { html, render } from 'nc-event/js/standalone.module.js'
import Event from 'nc-event'
render(html`<${Event} event=${{ content: "...", kind: 1 }} />`, document.body)Media Detection Functions
Import from nc-event/lib/media.js:
| Function | Description |
|----------|-------------|
| parseMedia(content) | Extract all media URLs from text |
| detectMediaType(url) | Returns 'image', 'video', 'audio', or null |
| detectPlatform(url) | Detect YouTube, Spotify, Vimeo, etc. |
| isImage(url) | Check if URL is an image |
| isVideo(url) | Check if URL is a video (file or platform) |
| isAudio(url) | Check if URL is audio (file or platform) |
| isMediaUrl(url) | Check if URL is any media type |
| getExtension(url) | Extract file extension from URL |
Media Detection
Supported Formats
Based on NIP-MEDIA Content Rendering Guidelines.
Images:
png, jpg, jpeg, gif, webp, avif, heic, svg, jxl, bmp, ico, tiff, tifVideo:
mp4, webm, mov, mkv, avi, m4v, 3gp, ogv, wmv, flv, m3u8Audio:
mp3, wav, flac, ogg, opus, aac, m4a, wma, aiff, apePlaylist:
m3uPlatform Embeds
| Platform | URL Patterns | Embed Type |
|----------|--------------|------------|
| YouTube | youtube.com/watch?v=, youtu.be/, youtube.com/shorts/ | Video |
| Spotify | open.spotify.com/(track\|album\|playlist)/ | Audio |
| Vimeo | vimeo.com/ | Video |
| Twitch | twitch.tv/ | Video |
| SoundCloud | soundcloud.com/ | Audio |
Edge Case Handling
The media detector correctly handles:
- ✅ Query parameters:
image.png?size=large - ✅ URL fragments:
image.jpg#section - ✅ Case insensitivity:
photo.PNG,VIDEO.MP4 - ✅ URL encoding:
my%20image.png - ❌ Rejects hidden files:
.png - ❌ Rejects double extensions:
file.png.exe - ❌ Rejects extension in query only:
?file=image.png
Testing
npm testRuns 88 unit tests covering:
- File extension extraction
- Media type detection (images, video, audio)
- Platform detection (YouTube, Spotify, Vimeo, etc.)
- Edge cases and security checks
Project Structure
nc-event/
├── lib/
│ ├── nc-event.js # <nc-event> custom element (use this!)
│ ├── index.js # Event Preact component
│ ├── media.js # Media detection module
│ └── m3u-parser.js # M3U playlist parser
├── test/
│ ├── media.test.js # Media detection tests
│ └── m3u-parser.test.js # M3U parser tests
├── js/
│ └── standalone.module.js # Bundled Preact + htm
└── examples/ # Live demosContributing
Contributions welcome! Please:
- Fork the repository
- Create a feature branch
- Run tests with
npm test - Submit a pull request
Related Projects
- nostr-tools — Nostr utilities
- Nostr Protocol — Protocol spec
- NIP-92 — Media Attachments
License
MIT © Melvin Carvalho
