import { Job } from "bullmq"; import { getPocketBaseClient } from "../util/pocketbase"; import type { Vod } from "../types"; const TWEET_URL_REGEX = /^https?:\/\/(twitter\.com|x\.com)\/[A-Za-z0-9_]{1,15}\/status\/(\d+)(\?.*)?$/; export function tweetIdToDate(id: string | number): Date { const snowflake = BigInt(id); const timestamp = (snowflake >> 22n) + 1288834974657n; return new Date(Number(timestamp)); } export function getTweetId(url: string) { if (!TWEET_URL_REGEX.test(url)) { throw new Error(`Invalid tweet URL: ${url}`); } return url.split('/').at(-1)!; } export function getTweetDates(tweetUrls: string[]): Date[] { tweetUrls.forEach((url) => { if (!TWEET_URL_REGEX.test(url)) { throw new Error(`Invalid tweet URL: ${url}`); } }); return tweetUrls .map(url => url.split('/').at(-1)!) // add ! if you’re sure it exists .map(tweetID => tweetIdToDate(tweetID)); } export async function getApplicableVods() { const pb = await getPocketBaseClient() const results = await pb.collection('vods').getList(1, 3, { filter: "videoSrcB2 != '' && magnetLink = ''" }) const vods = results.items; return vods; } /** * * createMagnetLink * * given a vod, scrape the tweet and populate the streamDate */ export async function createMagnetLinks(job: Job) { const pb = await getPocketBaseClient(); const vods = await getApplicableVods(); job.log(`getAnnounceUrlDetails found ${vods.length} vods in need of a streamDate.`) for (let i = 0; i < vods.length; i++) { const vod = vods[i]; const magnetLink = await createMagnetLink(vod.videoSrcB2); await pb.collection('vods').update(vod.id, { magnetLink }) const progress = Math.round(((i + 1) / vods.length) * 100); await job.updateProgress(progress); } } export async function createMagnetLink(vod: Vod) { }