nostr-web-components
Version:
collection of web components that provide quick access to basic nostr things
59 lines (53 loc) • 6.14 kB
JavaScript
var _=Object.defineProperty;var z=(l,o,a)=>o in l?_(l,o,{enumerable:!0,configurable:!0,writable:!0,value:a}):l[o]=a;var f=(l,o,a)=>z(l,typeof o!="symbol"?o+"":o,a);import{decodeNostrURI as B}from"@nostr/tools/nip19";import{normalizeURL as F}from"@nostr/tools/utils";import{b as W,p as G}from"./nostr.js";import{d as J}from"./utils.js";import"@nostr/tools/pool";import"@nostr/gadgets/lists";import"@nostr/gadgets/global";import"@nostr/gadgets/metadata";import"@nostr/tools/nip05";class O extends HTMLElement{constructor(){super();f(this,"root");f(this,"subc");f(this,"set",J(async()=>{this.subc&&this.subc.close();let a=this.getAttribute("ref");if(!a)return;let{type:i,data:p}=B(a),r=[],h,m;if(i==="nevent"){let e=p;r=e.relays||[],h=e.author,m={ids:[e.id]}}else if(i==="naddr"){let e=p;r=e.relays||[],h=e.pubkey,m={authors:[e.pubkey],kinds:[e.kind],"#d":[e.identifier]}}else if(a.match(/[0-9a-f]{64}/))m={ids:[a]};else{this.root.innerHTML='<p part="error"><slot name="error-pointer">not a valid livestream event pointer</slot></p>';return}if(r=r.map(F),h){let e=await W(h);r.push(...e)}let q=!1,k=!1,c;this.subc=G.subscribeMany(r,m,{label:"nostr-livestream",onevent:async e=>{var L,H,T,M,R,N,D,I,$;if(q=!0,e.kind!==30311){this.root.innerHTML='<p part="error"><slot name="error-invalid">event is not a livestream</slot></p>';return}const d=(L=e.tags.find(t=>t[0]==="title"))==null?void 0:L[1];if(d)for(let t of this.queryPart("title"))t.textContent=d;const v=(H=e.tags.find(t=>t[0]==="summary"))==null?void 0:H[1];if(v)for(let t of this.queryPart("summary"))t.textContent=v;const S=(T=e.tags.find(t=>t[0]==="image"))==null?void 0:T[1];if(S)for(let t of this.queryPart("image"))t.src=S;const w=((M=e.tags.find(t=>t[0]==="status"))==null?void 0:M[1])||"unknown";for(let t of this.queryPart("status"))t.textContent=w;const C=(R=e.tags.find(t=>t[0]==="current_participants"))==null?void 0:R[1];if(C){for(let t of this.queryPart("current"))t.style.display="block";for(let t of this.queryPart("current-value"))t.textContent=C}const E=(N=e.tags.find(t=>t[0]==="total_participants"))==null?void 0:N[1];if(E){for(let t of this.queryPart("total"))t.style.display="block";for(let t of this.queryPart("total-value"))t.textContent=E}const x=(D=e.tags.find(t=>t[0]==="starts"))==null?void 0:D[1],P=(I=e.tags.find(t=>t[0]==="ends"))==null?void 0:I[1];let b="";if(x){if(b=new Date(parseInt(x)*1e3).toLocaleString(),P){const s=new Date(parseInt(P)*1e3);b+=` to ${s.toLocaleString()}`}for(let s of this.queryPart("time"))s.textContent=b}let A=e.tags.filter(t=>t[0]==="p");if(A.length)for(let t of this.queryPart("participants")){let s=t.querySelector("template");if(s){let u=s.content;A.forEach(g=>{let j=u.cloneNode(),y=j.querySelector('[part="participant-pubkey"]');y&&(y.tagName==="NOSTR-NAME"?y.setAttribute("pubkey",g[1]):y.textContent=g[1]),j.querySelectorAll('[part="participant-role"]').forEach(U=>{U.textContent=g[3]||"participant"})})}}const n=($=e.tags.find(t=>t[0]==="streaming"))==null?void 0:$[1];if(w==="live"&&(n!=null&&n.endsWith(".m3u8"))){let t=this.root.querySelector("video");t.autoplay=this.hasAttribute("autoplay"),t.muted=this.hasAttribute("muted"),t.style.display="block";let s=t.querySelector("source");if(s.src!==n)if(s.src=n,!t.canPlayType("application/vnd.apple.mpegurl")&&!k){k=!0;const u=document.createElement("script");u.src="https://cdn.jsdelivr.net/npm/hls.js@latest",u.onload=()=>{window.Hls.isSupported()&&(c=new window.Hls,c.loadSource(n),c.attachMedia(t))},document.head.appendChild(u)}else c&&c.loadSource(n)}},oneose:()=>{var e,d;q||(this.root.innerHTML='<p part="error"><slot name="error-fetch">failed to fetch event</slot></p>',(d=(e=this.subc)==null?void 0:e.close)==null||d.call(e))}})},200));this.attachShadow({mode:"open"});const{shadowRoot:a}=this;this.root=document.createElement("div"),a.appendChild(this.root)}connectedCallback(){setTimeout(()=>{let a=this.getAttribute("template")?document.getElementById(this.getAttribute("template")):null;a?this.root.appendChild(a.content.cloneNode(!0)):this.root.innerHTML=`
<style>
header {
display: flex;
align-items: center;
}
header img {
height: 2em;
}
video {
width: 100%;
}
</style>
<slot name="header">
<header part="header">
<img part="image" />
<h3 part="title"></h3>
<p part="status"></p>
</header >
</slot>
<p part="time"></p>
<p part="summary"></p>
<section part="stats">
<slot name="stats">
<span part="current" style="display: none;">
current participants: <span part="current-value" />
</span>
<span part="total" style="display: none;">
total participants: <span part="total-value" />
</span>
</slot>
</section>
<video part="video" controls style="display: none;">
<source type="application/x-mpegURL">
your browser does not support HLS video playback
</video>
<section part="participants" style="display: none;">
<slot name="participants">
<h4 part="participants-title">
<slot name="participants-title"></slot>
</h4>
<ul part="participants-list">
<template>
<li part="participant-entry">
<nostr-name part="participant-pubkey" />
<span part="participant-role"></span>
</li>
</template>
</ul>
</slot>
</section>
`,this.set()},1)}*queryPart(a){let i=this.querySelectorAll(`[part="${a}"]`);for(let r=0;r<i.length;r++)yield i[r];let p=this.root.querySelectorAll(`[part="${a}"]`);for(let r=0;r<p.length;r++)yield p[r]}disconnectedCallback(){var a,i;(i=(a=this.subc)==null?void 0:a.close)==null||i.call(a)}attributeChangedCallback(){this.set()}}f(O,"observedAttributes",["ref","autoplay","muted"]);window.customElements.define("nostr-livestream",O);
//# sourceMappingURL=nostr-livestream.js.map