Merge pull request #13 from v0l/youtube

feat: embed youtube videos
This commit is contained in:
Kieran 2023-01-06 22:21:43 +00:00 committed by GitHub
commit 2f0a5a043e
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 62 additions and 32 deletions

View File

@ -8,7 +8,7 @@
<meta name="theme-color" content="#000000" /> <meta name="theme-color" content="#000000" />
<meta name="description" content="Fast nostr web ui" /> <meta name="description" content="Fast nostr web ui" />
<meta http-equiv="Content-Security-Policy" <meta http-equiv="Content-Security-Policy"
content="default-src 'self'; child-src 'none'; style-src 'self' 'unsafe-inline' https://fonts.googleapis.com; connect-src wss://* 'self' https://*; img-src * data:; font-src https://fonts.gstatic.com; media-src *; script-src 'self' https://static.cloudflareinsights.com;" /> content="default-src 'self'; child-src 'none'; frame-src youtube.com www.youtube.com; style-src 'self' 'unsafe-inline' https://fonts.googleapis.com; connect-src wss://* 'self' https://*; img-src * data:; font-src https://fonts.gstatic.com; media-src *; script-src 'self' https://static.cloudflareinsights.com;" />
<link rel="apple-touch-icon" href="%PUBLIC_URL%/nostrich_512.png" /> <link rel="apple-touch-icon" href="%PUBLIC_URL%/nostrich_512.png" />
<link rel="manifest" href="%PUBLIC_URL%/manifest.json" /> <link rel="manifest" href="%PUBLIC_URL%/manifest.json" />

View File

@ -57,3 +57,8 @@ export const MentionRegex = /(#\[\d+\])/gi;
* Simple lightning invoice regex * Simple lightning invoice regex
*/ */
export const InvoiceRegex = /(lnbc\w+)/i; export const InvoiceRegex = /(lnbc\w+)/i;
/**
* YouTube URL regex
*/
export const YoutubeUrlRegex = /^(?:https?:\/\/)?(?:www\.)?(?:youtu\.be\/|youtube\.com\/(?:embed\/|v\/|watch\?v=|watch\?.+&v=))((\w|-){11})(?:\S+)?$/

View File

@ -1,19 +1,17 @@
import { Link } from "react-router-dom"; import { Link } from "react-router-dom";
import Invoice from "./element/Invoice"; import Invoice from "./element/Invoice";
import { UrlRegex, FileExtensionRegex, MentionRegex, InvoiceRegex } from "./Const"; import { UrlRegex, FileExtensionRegex, MentionRegex, InvoiceRegex, YoutubeUrlRegex } from "./Const";
import { eventLink, profileLink } from "./Util"; import { eventLink, profileLink } from "./Util";
export function extractLinks(fragments) { function transformHttpLink(a) {
return fragments.map(f => {
if (typeof f === "string") {
return f.split(UrlRegex).map(a => {
if (a.startsWith("http")) {
try { try {
let url = new URL(a); const url = new URL(a);
let ext = url.pathname.toLowerCase().match(FileExtensionRegex); const vParam = url.searchParams.get('v')
if (ext) { const youtubeId = YoutubeUrlRegex.test(a) && RegExp.$1
switch (ext[1]) { const extension = FileExtensionRegex.test(url.pathname.toLowerCase()) && RegExp.$1
if (extension) {
switch (extension) {
case "gif": case "gif":
case "jpg": case "jpg":
case "jpeg": case "jpeg":
@ -29,7 +27,23 @@ export function extractLinks(fragments) {
case "m4v": { case "m4v": {
return <video key={url} src={url} controls /> return <video key={url} src={url} controls />
} }
default:
return <a key={url} href={url}>{url.toString()}</a>
} }
} else if (youtubeId) {
return (
<>
<br />
<iframe
src={`https://www.youtube.com/embed/${youtubeId}`}
title="YouTube video player"
frameborder="0"
allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share"
allowfullscreen=""
/>
<br />
</>
)
} else { } else {
return <a key={url} href={url}>{url.toString()}</a> return <a key={url} href={url}>{url.toString()}</a>
} }
@ -37,6 +51,14 @@ export function extractLinks(fragments) {
console.warn(`Not a valid url: ${a}`); console.warn(`Not a valid url: ${a}`);
} }
} }
export function extractLinks(fragments) {
return fragments.map(f => {
if (typeof f === "string") {
return f.split(UrlRegex).map(a => {
if (a.startsWith("http")) {
return transformHttpLink(a)
}
return a; return a;
}); });
} }

View File

@ -22,11 +22,15 @@
word-break: normal; word-break: normal;
} }
.note > .body > img, .note > .body > video { .note > .body > img, .note > .body > video, .note > .body > iframe {
max-width: 100%; max-width: 100%;
max-height: 500px; max-height: 500px;
} }
.note > .body > iframe {
margin: 10px 0;
}
.note > .header > img:hover, .note > .header > .name > .reply:hover, .note > .body:hover { .note > .header > img:hover, .note > .header > .name > .reply:hover, .note > .body:hover {
cursor: pointer; cursor: pointer;
} }

View File

@ -2,7 +2,6 @@ import { useEffect, useState } from "react";
import { useDispatch, useSelector } from "react-redux"; import { useDispatch, useSelector } from "react-redux";
import { useNavigate } from "react-router-dom"; import { useNavigate } from "react-router-dom";
import * as secp from '@noble/secp256k1'; import * as secp from '@noble/secp256k1';
import { bech32 } from "bech32";
import { setPrivateKey, setPublicKey } from "../state/Login"; import { setPrivateKey, setPublicKey } from "../state/Login";
import { EmailRegex } from "../Const"; import { EmailRegex } from "../Const";