mirror of
https://github.com/dergigi/boris.git
synced 2026-02-16 04:24:25 +01:00
- Replace @typescript-eslint/no-explicit-any with proper Filter type from nostr-tools/filter in dataFetch.ts and helpers.ts - Replace @typescript-eslint/no-explicit-any with IAccount and AccountManager types from applesauce-accounts in hooks - Replace @typescript-eslint/no-explicit-any with unknown type casts in App.tsx for keep-alive subscription - Fix react-hooks/exhaustive-deps warnings by including all dependencies in useEffect hooks - Remove unused _settings parameters in useImageCache.ts that were causing no-unused-vars warnings
126 lines
3.7 KiB
TypeScript
126 lines
3.7 KiB
TypeScript
// Extract pubkeys from nprofile strings in content
|
|
export const extractNprofilePubkeys = (content: string): string[] => {
|
|
const nprofileRegex = /nprofile1[a-z0-9]+/gi
|
|
const matches = content.match(nprofileRegex) || []
|
|
const unique = new Set<string>(matches)
|
|
return Array.from(unique)
|
|
}
|
|
|
|
export type UrlType = 'video' | 'image' | 'youtube' | 'article'
|
|
|
|
export interface UrlClassification {
|
|
type: UrlType
|
|
}
|
|
|
|
export const classifyUrl = (url: string | undefined): UrlClassification => {
|
|
if (!url) {
|
|
return { type: 'article' }
|
|
}
|
|
const urlLower = url.toLowerCase()
|
|
|
|
// Check for YouTube
|
|
if (urlLower.includes('youtube.com') || urlLower.includes('youtu.be')) {
|
|
return { type: 'youtube' }
|
|
}
|
|
|
|
// Check for popular video hosts
|
|
const videoHosts = ['vimeo.com', 'dailymotion.com', 'dai.ly', 'video.twimg.com']
|
|
if (videoHosts.some(host => urlLower.includes(host))) {
|
|
return { type: 'video' }
|
|
}
|
|
|
|
// Check for video extensions
|
|
const videoExtensions = ['.mp4', '.webm', '.ogg', '.mov', '.avi', '.mkv', '.m4v']
|
|
if (videoExtensions.some(ext => urlLower.includes(ext))) {
|
|
return { type: 'video' }
|
|
}
|
|
|
|
// Check for image extensions
|
|
const imageExtensions = ['.jpg', '.jpeg', '.png', '.gif', '.webp', '.svg', '.bmp', '.ico']
|
|
if (imageExtensions.some(ext => urlLower.includes(ext))) {
|
|
return { type: 'image' }
|
|
}
|
|
|
|
// Default to article
|
|
return { type: 'article' }
|
|
}
|
|
|
|
/**
|
|
* Checks if a relay URL is a local relay (localhost or 127.0.0.1)
|
|
*/
|
|
export const isLocalRelay = (relayUrl: string): boolean => {
|
|
return relayUrl.includes('localhost') || relayUrl.includes('127.0.0.1')
|
|
}
|
|
|
|
/**
|
|
* Checks if all relays in the list are local relays
|
|
*/
|
|
export const areAllRelaysLocal = (relayUrls: string[]): boolean => {
|
|
if (!relayUrls || relayUrls.length === 0) return false
|
|
return relayUrls.every(isLocalRelay)
|
|
}
|
|
|
|
/**
|
|
* Checks if at least one relay is a remote (non-local) relay
|
|
*/
|
|
export const hasRemoteRelay = (relayUrls: string[]): boolean => {
|
|
if (!relayUrls || relayUrls.length === 0) return false
|
|
return relayUrls.some(url => !isLocalRelay(url))
|
|
}
|
|
|
|
/**
|
|
* Splits relay URLs into local and remote groups
|
|
*/
|
|
export const partitionRelays = (
|
|
relayUrls: string[]
|
|
): { local: string[]; remote: string[] } => {
|
|
const local: string[] = []
|
|
const remote: string[] = []
|
|
for (const url of relayUrls) {
|
|
if (isLocalRelay(url)) local.push(url)
|
|
else remote.push(url)
|
|
}
|
|
return { local, remote }
|
|
}
|
|
|
|
/**
|
|
* Returns relays ordered with local first while keeping uniqueness
|
|
*/
|
|
export const prioritizeLocalRelays = (relayUrls: string[]): string[] => {
|
|
const { local, remote } = partitionRelays(relayUrls)
|
|
const seen = new Set<string>()
|
|
const out: string[] = []
|
|
for (const url of [...local, ...remote]) {
|
|
if (!seen.has(url)) {
|
|
seen.add(url)
|
|
out.push(url)
|
|
}
|
|
}
|
|
return out
|
|
}
|
|
|
|
// Parallel request helper
|
|
import { completeOnEose, onlyEvents, RelayPool } from 'applesauce-relay'
|
|
import { Observable, takeUntil, timer } from 'rxjs'
|
|
import { Filter } from 'nostr-tools/filter'
|
|
|
|
export function createParallelReqStreams(
|
|
relayPool: RelayPool,
|
|
localRelays: string[],
|
|
remoteRelays: string[],
|
|
filter: Filter,
|
|
localTimeoutMs = 1200,
|
|
remoteTimeoutMs = 6000
|
|
): { local$: Observable<unknown>; remote$: Observable<unknown> } {
|
|
const local$ = (localRelays.length > 0)
|
|
? relayPool.req(localRelays, filter).pipe(onlyEvents(), completeOnEose(), takeUntil(timer(localTimeoutMs)))
|
|
: new Observable<unknown>((sub) => { sub.complete() })
|
|
|
|
const remote$ = (remoteRelays.length > 0)
|
|
? relayPool.req(remoteRelays, filter).pipe(onlyEvents(), completeOnEose(), takeUntil(timer(remoteTimeoutMs)))
|
|
: new Observable<unknown>((sub) => { sub.complete() })
|
|
|
|
return { local$, remote$ }
|
|
}
|
|
|