UNPKG

social-link-parser

Version:

Extract usernames, IDs, and metadata from social media URLs across 100+ platforms

87 lines 3.34 kB
import { Platforms } from '../../core/types.js'; import { normalize } from '../../utils/url.js'; import { createDomainPattern } from '../../utils/url.js'; import { QUERY_HASH } from '../../utils/constants.js'; const domains = ['twitter.com', 'x.com', 'platform.twitter.com']; const subdomains = ['m', 'mobile']; const DOMAIN_PATTERN = createDomainPattern(domains, subdomains); export const twitter = { id: Platforms.Twitter, name: 'Twitter', color: '#1DA1F2', domains: domains, subdomains: subdomains, patterns: { profile: new RegExp(`^https?://${DOMAIN_PATTERN}/([A-Za-z0-9_]{2,15})/?${QUERY_HASH}$`, 'i'), handle: /^@?[A-Za-z0-9_]{1,15}$/, content: { post: new RegExp(`^https?://${DOMAIN_PATTERN}/([A-Za-z0-9_]{2,15})/status/(\\d{10,20})/?${QUERY_HASH}$`, 'i'), embed: new RegExp(`^https?://${DOMAIN_PATTERN}/embed/Tweet\\.html\\?id=(\\d{10,20})(?:&.*)?${QUERY_HASH}$`, 'i'), }, }, detect(url) { if (!this.domains.some(d => url.includes(d))) return false; if (this.patterns.profile.test(url)) return true; if (this.patterns.content?.post?.test(url)) return true; if (this.patterns.content?.embed?.test(url)) return true; return false; }, extract(url, result) { const embedMatch = this.patterns.content?.embed?.exec(url); if (embedMatch) { result.ids.tweetId = embedMatch[1]; result.metadata.isEmbed = true; result.metadata.contentType = 'embed'; return; } const postMatch = this.patterns.content?.post?.exec(url); if (postMatch) { result.username = postMatch[1]; result.ids.tweetId = postMatch[2]; result.metadata.isPost = true; result.metadata.contentType = 'post'; return; } const profileMatch = this.patterns.profile.exec(url); if (profileMatch) { result.username = profileMatch[1]; result.metadata.isProfile = true; result.metadata.contentType = 'profile'; } }, validateHandle(handle) { const cleaned = handle.replace('@', ''); return /^[A-Za-z0-9_]{1,15}$/.test(cleaned); }, buildProfileUrl(username) { const clean = username.replace('@', ''); return `https://x.com/${clean}`; }, buildContentUrl(contentType, id) { if (contentType === 'post') { return `https://x.com/i/status/${id}`; } return `https://x.com/${id}`; }, normalizeUrl(url) { url = url.replace('twitter.com', 'x.com'); url = url.replace(/[?&](s|t|ref_src)=[^&]+/g, ''); return normalize(url); }, getEmbedInfo(url, parsed) { if (url.includes('twitframe.com')) { return { embedUrl: url, isEmbedAlready: true }; } if (parsed.ids.tweetId) { const tweetUrl = this.buildContentUrl ? this.buildContentUrl('post', parsed.ids.tweetId) : `https://x.com/i/status/${parsed.ids.tweetId}`; const embedUrl = `https://twitframe.com/show?url=${encodeURIComponent(tweetUrl)}`; return { embedUrl, type: 'iframe' }; } return null; }, }; //# sourceMappingURL=index.js.map