Live (#8354)
This commit is contained in:
@@ -0,0 +1,51 @@
|
||||
import {useMemo} from 'react'
|
||||
import {
|
||||
type $Typed,
|
||||
type AppBskyActorDefs,
|
||||
type AppBskyEmbedExternal,
|
||||
} from '@atproto/api'
|
||||
import {isAfter, parseISO} from 'date-fns'
|
||||
|
||||
import {useMaybeProfileShadow} from '#/state/cache/profile-shadow'
|
||||
import {useTickEveryMinute} from '#/state/shell'
|
||||
import {temp__canBeLive, temp__isStatusValid} from '#/components/live/temp'
|
||||
import type * as bsky from '#/types/bsky'
|
||||
|
||||
export function useActorStatus(actor?: bsky.profile.AnyProfileView) {
|
||||
const shadowed = useMaybeProfileShadow(actor)
|
||||
const tick = useTickEveryMinute()
|
||||
return useMemo(() => {
|
||||
tick! // revalidate every minute
|
||||
|
||||
if (
|
||||
shadowed &&
|
||||
temp__canBeLive(shadowed) &&
|
||||
'status' in shadowed &&
|
||||
shadowed.status &&
|
||||
temp__isStatusValid(shadowed.status) &&
|
||||
isStatusStillActive(shadowed.status.expiresAt)
|
||||
) {
|
||||
return {
|
||||
isActive: true,
|
||||
status: 'app.bsky.actor.status#live',
|
||||
embed: shadowed.status.embed as $Typed<AppBskyEmbedExternal.View>, // temp_isStatusValid asserts this
|
||||
expiresAt: shadowed.status.expiresAt!, // isStatusStillActive asserts this
|
||||
record: shadowed.status.record,
|
||||
} satisfies AppBskyActorDefs.StatusView
|
||||
} else {
|
||||
return {
|
||||
status: '',
|
||||
isActive: false,
|
||||
record: {},
|
||||
} satisfies AppBskyActorDefs.StatusView
|
||||
}
|
||||
}, [shadowed, tick])
|
||||
}
|
||||
|
||||
export function isStatusStillActive(timeStr: string | undefined) {
|
||||
if (!timeStr) return false
|
||||
const now = new Date()
|
||||
const expiry = parseISO(timeStr)
|
||||
|
||||
return isAfter(expiry, now)
|
||||
}
|
||||
@@ -1,10 +1,10 @@
|
||||
import {
|
||||
AppBskyFeedDefs,
|
||||
AppBskyGraphDefs,
|
||||
ComAtprotoRepoStrongRef,
|
||||
type AppBskyFeedDefs,
|
||||
type AppBskyGraphDefs,
|
||||
type ComAtprotoRepoStrongRef,
|
||||
} from '@atproto/api'
|
||||
import {AtUri} from '@atproto/api'
|
||||
import {BskyAgent} from '@atproto/api'
|
||||
import {type BskyAgent} from '@atproto/api'
|
||||
|
||||
import {POST_IMG_MAX} from '#/lib/constants'
|
||||
import {getLinkMeta} from '#/lib/link-meta/link-meta'
|
||||
@@ -22,9 +22,9 @@ import {
|
||||
isBskyStartUrl,
|
||||
isShortLink,
|
||||
} from '#/lib/strings/url-helpers'
|
||||
import {ComposerImage} from '#/state/gallery'
|
||||
import {type ComposerImage} from '#/state/gallery'
|
||||
import {createComposerImage} from '#/state/gallery'
|
||||
import {Gif} from '#/state/queries/tenor'
|
||||
import {type Gif} from '#/state/queries/tenor'
|
||||
import {createGIFDescription} from '../gif-alt-text'
|
||||
import {convertBskyAppUrlIfNeeded, makeRecordUri} from '../strings/url-helpers'
|
||||
|
||||
@@ -213,7 +213,7 @@ async function resolveExternal(
|
||||
}
|
||||
}
|
||||
|
||||
async function imageToThumb(
|
||||
export async function imageToThumb(
|
||||
imageUri: string,
|
||||
): Promise<ComposerImage | undefined> {
|
||||
try {
|
||||
|
||||
@@ -31,6 +31,7 @@ export const DISCOVER_DEBUG_DIDS: Record<string, true> = {
|
||||
'did:plc:3jpt2mvvsumj2r7eqk4gzzjz': true, // esb.lol
|
||||
'did:plc:vjug55kidv6sye7ykr5faxxn': true, // emilyliu.me
|
||||
'did:plc:tgqseeot47ymot4zro244fj3': true, // iwsmith.bsky.social
|
||||
'did:plc:2dzyut5lxna5ljiaasgeuffz': true, // mrnuma.bsky.social
|
||||
}
|
||||
|
||||
const BASE_FEEDBACK_FORM_URL = `${HELP_DESK_URL}/requests/new`
|
||||
|
||||
@@ -372,3 +372,33 @@ export function getServiceAuthAudFromUrl(url: string | URL): string | null {
|
||||
}
|
||||
return `did:web:${hostname}`
|
||||
}
|
||||
|
||||
// passes URL.parse, and has a TLD etc
|
||||
export function definitelyUrl(maybeUrl: string) {
|
||||
try {
|
||||
if (maybeUrl.endsWith('.')) return null
|
||||
|
||||
// Prepend 'https://' if the input doesn't start with a protocol
|
||||
if (!maybeUrl.startsWith('https://') && !maybeUrl.startsWith('http://')) {
|
||||
maybeUrl = 'https://' + maybeUrl
|
||||
}
|
||||
|
||||
const url = new URL(maybeUrl)
|
||||
|
||||
// Extract the hostname and split it into labels
|
||||
const hostname = url.hostname
|
||||
const labels = hostname.split('.')
|
||||
|
||||
// Ensure there are at least two labels (e.g., 'example' and 'com')
|
||||
if (labels.length < 2) return null
|
||||
|
||||
const tld = labels[labels.length - 1]
|
||||
|
||||
// Check that the TLD is at least two characters long and contains only letters
|
||||
if (!/^[a-z]{2,}$/i.test(tld)) return null
|
||||
|
||||
return url.toString()
|
||||
} catch {
|
||||
return null
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user