67 lines
2.3 KiB
TypeScript
67 lines
2.3 KiB
TypeScript
/** Threads Graph API reply_to_id must be a numeric media id (pk), not a URL shortcode. */
|
|
|
|
export function isNumericMediaId(raw?: string | null): boolean {
|
|
const value = (raw || '').trim()
|
|
if (value.length < 8) return false
|
|
return /^\d+$/.test(value)
|
|
}
|
|
|
|
export function shortcodeFromPermalink(permalink?: string | null): string {
|
|
const link = (permalink || '').trim().split('?')[0].split('#')[0]
|
|
const match = link.match(/threads\.(?:com|net)\/@[^/]+\/post\/([^/?#]+)/i)
|
|
return match?.[1]?.trim() || ''
|
|
}
|
|
|
|
export function mediaIdFromThreadObject(obj: Record<string, unknown>): string | undefined {
|
|
if (obj.pk != null) {
|
|
const pk = String(obj.pk).trim()
|
|
if (isNumericMediaId(pk)) return pk
|
|
}
|
|
if (obj.id != null) {
|
|
const id = String(obj.id).trim()
|
|
if (isNumericMediaId(id)) return id
|
|
}
|
|
return undefined
|
|
}
|
|
|
|
export function postShortcode(obj: Record<string, unknown>): string | undefined {
|
|
const code = typeof obj.code === 'string' ? obj.code.trim() : ''
|
|
return code || undefined
|
|
}
|
|
|
|
type PostWithMedia = {
|
|
externalId?: string
|
|
permalink?: string
|
|
}
|
|
|
|
/** Upgrade shortcode-only crawler rows when JSON/network capture found numeric pk for same post. */
|
|
export function enrichPostsWithMediaIds<T extends PostWithMedia>(posts: T[]): T[] {
|
|
const numericByShortcode = new Map<string, string>()
|
|
|
|
for (const post of posts) {
|
|
const externalId = (post.externalId || '').trim()
|
|
const shortcode = shortcodeFromPermalink(post.permalink) || (!isNumericMediaId(externalId) ? externalId : '')
|
|
if (shortcode && isNumericMediaId(externalId)) {
|
|
numericByShortcode.set(shortcode.toLowerCase(), externalId)
|
|
}
|
|
}
|
|
|
|
return posts.map((post) => {
|
|
const externalId = (post.externalId || '').trim()
|
|
if (isNumericMediaId(externalId)) return post
|
|
const shortcode = shortcodeFromPermalink(post.permalink) || externalId
|
|
if (!shortcode) return post
|
|
const numeric = numericByShortcode.get(shortcode.toLowerCase())
|
|
if (!numeric) return post
|
|
return { ...post, externalId: numeric }
|
|
})
|
|
}
|
|
|
|
export function preferReplyExternalId(existing?: string, incoming?: string): string {
|
|
const a = (existing || '').trim()
|
|
const b = (incoming || '').trim()
|
|
if (isNumericMediaId(a)) return a
|
|
if (isNumericMediaId(b)) return b
|
|
if (b) return b
|
|
return a
|
|
} |