2025-12-18 19:27:30 +00:00
|
|
|
import 'dotenv/config'
|
2025-12-18 01:57:14 +00:00
|
|
|
|
2025-12-25 20:01:41 +00:00
|
|
|
import { items, linkFormat } from './config.js'
|
2025-12-28 16:56:40 +00:00
|
|
|
import {
|
|
|
|
|
getAtomFeed,
|
|
|
|
|
getHardcoverActivity,
|
|
|
|
|
getJsonFeedItemTitle,
|
|
|
|
|
getLetterboxdActivity,
|
|
|
|
|
getListenBrainzScrobble,
|
2025-12-28 17:23:27 +00:00
|
|
|
getMalojaScrobble,
|
2025-12-28 16:56:40 +00:00
|
|
|
getMastodonPost,
|
|
|
|
|
getRSSItemTitle,
|
2025-12-28 20:51:19 +00:00
|
|
|
getSomePicsPost,
|
2025-12-28 16:56:40 +00:00
|
|
|
getSourceTubeActivity,
|
|
|
|
|
getSteamRecentlyPlayed,
|
|
|
|
|
getTraktEpisode,
|
|
|
|
|
getTraktMovie,
|
|
|
|
|
htmlServiceLinkRegex,
|
|
|
|
|
markdownCharEscape,
|
|
|
|
|
markdownServiceLinkRegex,
|
|
|
|
|
} from './utils.js'
|
|
|
|
|
|
|
|
|
|
const feedHandlers = {
|
|
|
|
|
rss: getRSSItemTitle,
|
|
|
|
|
atom: getAtomFeed,
|
|
|
|
|
json: getJsonFeedItemTitle,
|
2025-12-28 20:51:19 +00:00
|
|
|
'some.pics': getSomePicsPost,
|
2025-12-28 16:56:40 +00:00
|
|
|
'source.tube': getSourceTubeActivity,
|
|
|
|
|
mastodon: getMastodonPost,
|
|
|
|
|
letterboxd: getLetterboxdActivity,
|
|
|
|
|
'trakt-episode': getTraktEpisode,
|
|
|
|
|
'trakt-movie': getTraktMovie,
|
|
|
|
|
steam: getSteamRecentlyPlayed,
|
|
|
|
|
listenbrainz: getListenBrainzScrobble,
|
2025-12-28 17:23:27 +00:00
|
|
|
maloja: getMalojaScrobble,
|
2025-12-28 16:56:40 +00:00
|
|
|
hardcover: getHardcoverActivity,
|
|
|
|
|
}
|
2025-12-18 01:57:14 +00:00
|
|
|
|
2025-12-18 19:27:30 +00:00
|
|
|
const OMGLOL_API = `https://api.omg.lol/address/${process.env.OMGLOL_USERNAME}/now`
|
2025-12-18 01:57:14 +00:00
|
|
|
|
|
|
|
|
export async function getNow() {
|
2025-12-18 19:27:30 +00:00
|
|
|
const res = await fetch(OMGLOL_API)
|
|
|
|
|
const data = await res.json()
|
|
|
|
|
return data.response.now.content
|
2025-12-18 01:57:14 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
export async function setNow(newNow) {
|
|
|
|
|
const res = await fetch(OMGLOL_API, {
|
2025-12-18 19:27:30 +00:00
|
|
|
method: 'POST',
|
2025-12-18 01:57:14 +00:00
|
|
|
headers: {
|
2025-12-18 19:27:30 +00:00
|
|
|
'Content-Type': 'application/json',
|
2025-12-18 01:57:14 +00:00
|
|
|
Authorization: `Bearer ${process.env.OMGLOL_KEY}`,
|
|
|
|
|
},
|
|
|
|
|
body: JSON.stringify({
|
|
|
|
|
content: newNow,
|
|
|
|
|
listed: 1,
|
|
|
|
|
}),
|
2025-12-18 19:27:30 +00:00
|
|
|
})
|
|
|
|
|
const data = await res.json()
|
|
|
|
|
console.log(`\n${data.response.message}`)
|
2025-12-18 01:57:14 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
export default async function now() {
|
2025-12-18 19:27:30 +00:00
|
|
|
const now = await getNow()
|
|
|
|
|
let newNow = now
|
2025-12-18 01:57:14 +00:00
|
|
|
|
|
|
|
|
await Promise.all(
|
2025-12-28 16:56:40 +00:00
|
|
|
items.map(async (item) => {
|
2025-12-18 19:27:30 +00:00
|
|
|
try {
|
2025-12-28 16:56:40 +00:00
|
|
|
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 || '')
|
|
|
|
|
}
|
|
|
|
|
|
2025-12-28 17:32:17 +00:00
|
|
|
// generic handlers expect just feedUrl string, special handlers expect config object
|
2025-12-28 20:51:19 +00:00
|
|
|
const handlerParam = [
|
|
|
|
|
'rss',
|
|
|
|
|
'atom',
|
|
|
|
|
'json',
|
|
|
|
|
'maloja',
|
|
|
|
|
'some.pics',
|
|
|
|
|
].includes(item.feedType)
|
2025-12-28 17:32:17 +00:00
|
|
|
? feedUrl
|
|
|
|
|
: { ...item, feedUrl }
|
|
|
|
|
const latest = await handler(handlerParam)
|
2025-12-28 16:56:40 +00:00
|
|
|
console.log(`${item.id}: ${latest.text}`)
|
|
|
|
|
console.log(`${item.id} URL: ${latest.url}`)
|
2025-12-28 21:10:08 +00:00
|
|
|
if (latest.image) console.log(`${item.id} Image: ${latest.image}`)
|
|
|
|
|
if (latest.video) console.log(`${item.id} Video: ${latest.video}`)
|
2025-12-25 20:01:41 +00:00
|
|
|
|
2025-12-31 00:03:59 +00:00
|
|
|
// apply markdown escaping only for markdown links
|
2025-12-25 20:01:41 +00:00
|
|
|
const displayText =
|
|
|
|
|
linkFormat === 'html'
|
|
|
|
|
? latest.text
|
|
|
|
|
: markdownCharEscape(latest.text)
|
|
|
|
|
|
2025-12-25 18:30:40 +00:00
|
|
|
if (latest && latest.text && latest.url) {
|
2025-12-28 16:56:40 +00:00
|
|
|
// generate regex based on id and linkFormat
|
|
|
|
|
const regex =
|
|
|
|
|
linkFormat === 'html'
|
|
|
|
|
? htmlServiceLinkRegex(item.id)
|
|
|
|
|
: markdownServiceLinkRegex(item.id)
|
|
|
|
|
|
2025-12-31 00:03:59 +00:00
|
|
|
console.log(`\nDEBUG: Testing regex for ${item.id}`)
|
|
|
|
|
console.log(`Regex: ${regex}`)
|
|
|
|
|
const matched = regex.test(newNow)
|
|
|
|
|
console.log(`Regex match found: ${matched}`)
|
|
|
|
|
|
2025-12-31 00:19:26 +00:00
|
|
|
newNow = newNow.replace(regex, (match, openTag, oldText, closeTag) => {
|
2025-12-31 00:03:59 +00:00
|
|
|
console.log(`DEBUG: Replacing match for ${item.id}`)
|
|
|
|
|
console.log(`Old match: ${match}`)
|
2025-12-31 00:19:26 +00:00
|
|
|
console.log(`Old text: ${oldText}`)
|
2025-12-31 00:03:59 +00:00
|
|
|
// replace href in opening tag
|
2025-12-25 18:30:40 +00:00
|
|
|
const updatedOpenTag = openTag.replace(
|
|
|
|
|
/href=["'][^"']*["']/,
|
|
|
|
|
`href="${latest.url}"`,
|
|
|
|
|
)
|
2025-12-31 00:03:59 +00:00
|
|
|
const result = `${updatedOpenTag}${displayText}${closeTag}`
|
|
|
|
|
console.log(`New replacement: ${result}`)
|
|
|
|
|
return result
|
2025-12-25 18:30:40 +00:00
|
|
|
})
|
2025-12-28 17:45:59 +00:00
|
|
|
|
2025-12-28 19:11:54 +00:00
|
|
|
// replace image/video placeholders if available, otherwise remove tags
|
2025-12-28 19:08:32 +00:00
|
|
|
const imageId = `${item.id}-image`
|
2025-12-28 19:11:54 +00:00
|
|
|
const videoId = `${item.id}-video`
|
2025-12-28 17:45:59 +00:00
|
|
|
if (latest.image) {
|
2026-01-01 19:53:45 +00:00
|
|
|
// html image replacement - match by data-service attribute to allow repeated updates
|
|
|
|
|
newNow = newNow.replace(
|
|
|
|
|
new RegExp(`(<img[^>]*data-service=["']${item.id}["'][^>]*\\bsrc=["'])[^"']*?(["'][^>]*>)`, 'gi'),
|
|
|
|
|
`$1${latest.image}$2`,
|
|
|
|
|
)
|
|
|
|
|
// also handle initial placeholder case
|
2025-12-28 17:45:59 +00:00
|
|
|
newNow = newNow.replace(
|
|
|
|
|
new RegExp(`(<img[^>]+src=["'])${imageId}(["'][^>]*>)`, 'gi'),
|
|
|
|
|
`$1${latest.image}$2`,
|
|
|
|
|
)
|
|
|
|
|
// markdown image replacement
|
|
|
|
|
newNow = newNow.replace(
|
|
|
|
|
new RegExp(`(!\\[[^\\]]*\\]\\()${imageId}(\\))`, 'gi'),
|
|
|
|
|
`$1${latest.image}$2`,
|
|
|
|
|
)
|
2025-12-28 19:08:32 +00:00
|
|
|
} else {
|
2026-01-01 19:53:45 +00:00
|
|
|
// remove img tags if no image available - match by data-service attribute
|
|
|
|
|
newNow = newNow.replace(
|
|
|
|
|
new RegExp(`\\s*<img\\b[^>]*\\bdata-service=["']${item.id}["'][^>]*>\\s*`, 'gis'),
|
|
|
|
|
'',
|
|
|
|
|
)
|
|
|
|
|
// also remove by placeholder src
|
2025-12-28 19:08:32 +00:00
|
|
|
newNow = newNow.replace(
|
2025-12-28 21:22:42 +00:00
|
|
|
new RegExp(`\\s*<img\\b[^>]*\\bsrc=["']${imageId}["'][^>]*>\\s*`, 'gis'),
|
2025-12-28 19:08:32 +00:00
|
|
|
'',
|
|
|
|
|
)
|
|
|
|
|
// remove markdown image
|
|
|
|
|
newNow = newNow.replace(
|
|
|
|
|
new RegExp(`!\\[[^\\]]*\\]\\(${imageId}\\)`, 'gi'),
|
|
|
|
|
'',
|
|
|
|
|
)
|
2025-12-28 17:45:59 +00:00
|
|
|
}
|
2025-12-28 19:11:54 +00:00
|
|
|
|
|
|
|
|
if (latest.video) {
|
2026-01-01 19:53:45 +00:00
|
|
|
// html video replacement - match by data-service attribute to allow repeated updates
|
|
|
|
|
newNow = newNow.replace(
|
|
|
|
|
new RegExp(`(<video[^>]*data-service=["']${item.id}["'][^>]*\\bsrc=["'])[^"']*?(["'][^>]*>)`, 'gi'),
|
|
|
|
|
`$1${latest.video}$2`,
|
|
|
|
|
)
|
|
|
|
|
// also handle initial placeholder case
|
2025-12-28 19:11:54 +00:00
|
|
|
newNow = newNow.replace(
|
|
|
|
|
new RegExp(`(<video[^>]+src=["'])${videoId}(["'][^>]*>)`, 'gi'),
|
|
|
|
|
`$1${latest.video}$2`,
|
|
|
|
|
)
|
|
|
|
|
} else {
|
2026-01-01 19:53:45 +00:00
|
|
|
// remove video tags if no video available - match by data-service attribute
|
|
|
|
|
newNow = newNow.replace(
|
|
|
|
|
new RegExp(`\\s*<video\\b[^>]*\\bdata-service=["']${item.id}["'][^>]*>[\\s\\S]*?</video>\\s*`, 'gis'),
|
|
|
|
|
'',
|
|
|
|
|
)
|
|
|
|
|
// also remove by placeholder src
|
2025-12-28 19:11:54 +00:00
|
|
|
newNow = newNow.replace(
|
2025-12-28 21:22:42 +00:00
|
|
|
new RegExp(`\\s*<video\\b[^>]*\\bsrc=["']${videoId}["'][^>]*>[\\s\\S]*?</video>\\s*`, 'gis'),
|
2025-12-28 19:11:54 +00:00
|
|
|
'',
|
|
|
|
|
)
|
|
|
|
|
}
|
2025-12-18 19:27:30 +00:00
|
|
|
}
|
|
|
|
|
} catch (e) {
|
2025-12-28 17:29:09 +00:00
|
|
|
console.warn(`⚠️ Failed to fetch ${item.id}`, e)
|
2025-12-18 01:57:14 +00:00
|
|
|
}
|
|
|
|
|
}),
|
2025-12-18 19:27:30 +00:00
|
|
|
)
|
2025-12-18 01:57:14 +00:00
|
|
|
|
2025-12-31 00:03:59 +00:00
|
|
|
console.log('\n=== FINAL COMPARISON ===')
|
|
|
|
|
console.log(`Original length: ${now.length}`)
|
|
|
|
|
console.log(`New length: ${newNow.length}`)
|
|
|
|
|
console.log(`Strings are equal: ${now === newNow}`)
|
|
|
|
|
|
2025-12-18 01:57:14 +00:00
|
|
|
if (now === newNow) {
|
2025-12-18 19:27:30 +00:00
|
|
|
console.log('\nNow page has no changes')
|
2025-12-18 01:57:14 +00:00
|
|
|
} else {
|
2025-12-31 00:03:59 +00:00
|
|
|
console.log('\nChanges detected! Updating Now page...')
|
2025-12-18 19:27:30 +00:00
|
|
|
await setNow(newNow)
|
2025-12-18 01:57:14 +00:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2025-12-18 19:27:30 +00:00
|
|
|
await now()
|