import 'dotenv/config' import { items, linkFormat } from './config.js' import { getAtomFeed, getHardcoverActivity, getJsonFeedItemTitle, getLetterboxdActivity, getListenBrainzScrobble, getMalojaScrobble, getMastodonPost, getRSSItemTitle, getSourceTubeActivity, getSteamRecentlyPlayed, getTraktEpisode, getTraktMovie, htmlServiceLinkRegex, markdownCharEscape, markdownServiceLinkRegex, } from './utils.js' const feedHandlers = { rss: getRSSItemTitle, atom: getAtomFeed, json: getJsonFeedItemTitle, 'source.tube': getSourceTubeActivity, mastodon: getMastodonPost, letterboxd: getLetterboxdActivity, 'trakt-episode': getTraktEpisode, 'trakt-movie': getTraktMovie, steam: getSteamRecentlyPlayed, listenbrainz: getListenBrainzScrobble, maloja: getMalojaScrobble, hardcover: getHardcoverActivity, } const OMGLOL_API = `https://api.omg.lol/address/${process.env.OMGLOL_USERNAME}/now` export async function getNow() { const res = await fetch(OMGLOL_API) const data = await res.json() return data.response.now.content } export async function setNow(newNow) { const res = await fetch(OMGLOL_API, { method: 'POST', headers: { 'Content-Type': 'application/json', Authorization: `Bearer ${process.env.OMGLOL_KEY}`, }, body: JSON.stringify({ content: newNow, listed: 1, }), }) const data = await res.json() console.log(`\n${data.response.message}`) } export default async function now() { const now = await getNow() let newNow = now await Promise.all( items.map(async (item) => { try { const handler = feedHandlers[item.feedType] if (!handler) { throw new Error(`Unknown feedType: ${item.feedType}`) } // build feedUrl from template if provided let feedUrl = item.feedUrl if (item.feedUrlTemplate) { feedUrl = item.feedUrlTemplate .replace('{userId}', item.userId || '') .replace('{instance}', item.instance || '') } // generic handlers expect just feedUrl string, special handlers expect config object const handlerParam = ['rss', 'atom', 'json', 'maloja'].includes( item.feedType, ) ? feedUrl : { ...item, feedUrl } const latest = await handler(handlerParam) console.log(`${item.id}: ${latest.text}`) console.log(`${item.id} URL: ${latest.url}`) // Apply markdown escaping only for markdown links const displayText = linkFormat === 'html' ? latest.text : markdownCharEscape(latest.text) if (latest && latest.text && latest.url) { // generate regex based on id and linkFormat const regex = linkFormat === 'html' ? htmlServiceLinkRegex(item.id) : markdownServiceLinkRegex(item.id) newNow = newNow.replace(regex, (match, openTag, closeTag) => { // Replace href in opening tag const updatedOpenTag = openTag.replace( /href=["'][^"']*["']/, `href="${latest.url}"`, ) return `${updatedOpenTag}${displayText}${closeTag}` }) // replace image placeholders if image is available, otherwise remove img tags const imageId = `${item.id}-image` if (latest.image) { // html image replacement newNow = newNow.replace( new RegExp(`(]+src=["'])${imageId}(["'][^>]*>)`, 'gi'), `$1${latest.image}$2`, ) // markdown image replacement newNow = newNow.replace( new RegExp(`(!\\[[^\\]]*\\]\\()${imageId}(\\))`, 'gi'), `$1${latest.image}$2`, ) } else { // remove img tags if no image available newNow = newNow.replace( new RegExp(`]+src=["']${imageId}["'][^>]*>`, 'gi'), '', ) // remove markdown image newNow = newNow.replace( new RegExp(`!\\[[^\\]]*\\]\\(${imageId}\\)`, 'gi'), '', ) } } } catch (e) { console.warn(`⚠️ Failed to fetch ${item.id}`, e) } }), ) if (now === newNow) { console.log('\nNow page has no changes') } else { await setNow(newNow) } } await now()