diff --git a/index.js b/index.js
index c387272..15d15c4 100644
--- a/index.js
+++ b/index.js
@@ -79,7 +79,7 @@ export default async function now() {
}
// generic handlers expect just feedUrl string, special handlers expect config object
- const handlerParam = ['rss', 'atom', 'json', 'mastodon', 'maloja'].includes(
+ const handlerParam = ['rss', 'atom', 'json', 'maloja'].includes(
item.feedType,
)
? feedUrl
@@ -109,6 +109,21 @@ export default async function now() {
)
return `${updatedOpenTag}${displayText}${closeTag}`
})
+
+ // replace image placeholders if image is available
+ if (latest.image) {
+ const imageId = `${item.id}-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`,
+ )
+ }
}
} catch (e) {
console.warn(`⚠️ Failed to fetch ${item.id}`, e)
diff --git a/services.js b/services.js
index 7d8c344..a52273a 100644
--- a/services.js
+++ b/services.js
@@ -64,6 +64,7 @@ export const services = [
instance: 'social.lol', // your mastodon instance
feedUrlTemplate: 'https://{instance}/@{userId}.rss',
feedType: 'mastodon',
+ showImage: false,
},
{
id: 'pixelfed',
@@ -90,7 +91,7 @@ export const services = [
userId: 'stfudonny', // your letterboxd username
feedUrlTemplate: 'https://letterboxd.com/{userId}/rss/',
feedType: 'letterboxd',
- showImage: false,
+ showImage: true,
},
{
id: 'trakt-episode',
@@ -98,7 +99,7 @@ export const services = [
userId: 'crankle', // your trakt username
traktId: '78e1e87b446901f7e4f0883dd4995cec', // your trakt ID
feedType: 'trakt-episode',
- showImage: false,
+ showImage: true,
},
{
id: 'trakt-movie',
@@ -106,7 +107,7 @@ export const services = [
userId: 'crankle', // your trakt username
traktId: '78e1e87b446901f7e4f0883dd4995cec', // your trakt ID
feedType: 'trakt-movie',
- showImage: false,
+ showImage: true,
},
// ========================================================================
diff --git a/utils.js b/utils.js
index 0a59f69..bb76488 100644
--- a/utils.js
+++ b/utils.js
@@ -78,18 +78,13 @@ export async function getAtomFeed(url) {
}
// json feed parser - grabs the latest item title
-// optionally includes images in markdown format
+// optionally includes images separately
export async function getJsonFeedItemTitle(feedUrl, showImage = true) {
const res = await fetch(feedUrl)
const data = await res.json()
const post = data.items[0]
const { title, image, url } = post
- const text = !showImage
- ? title
- : image
- ? `${title} `
- : title
- return { text, url }
+ return { text: title, url, image: showImage ? image : null }
}
// ========================================================================
@@ -133,7 +128,10 @@ export async function getMalojaScrobble(malojaUrl) {
// mastodon rss feed parser - filters out replies (posts starting with @)
// also replaces urls with 🔗 emoji to keep things tidy
-export async function getMastodonPost(feedUrl) {
+// extracts images from posts if available
+export async function getMastodonPost(config) {
+ const { feedUrl, showImage = false } =
+ typeof config === 'string' ? { feedUrl: config } : config
const res = await fetch(feedUrl)
const data = await res.text()
const dom = new JSDOM(data, { contentType: 'text/xml' })
@@ -152,6 +150,10 @@ export async function getMastodonPost(feedUrl) {
const link = item.querySelector('link')?.textContent.trim()
+ // extract image from description html if available
+ const imgMatch = description.match(/
]+src="([^"]+)"/)
+ const image = imgMatch ? imgMatch[1] : null
+
// use description as the text, stripping HTML
let cleanText = sanitizeHtml(description, {
allowedTags: [],
@@ -161,20 +163,26 @@ export async function getMastodonPost(feedUrl) {
// replace URLs with a link emoji
cleanText = cleanText.replace(/https?:\/\/\S+/g, '🔗').trim()
- return { text: cleanText, url: link }
+ return { text: cleanText, url: link, image: showImage ? image : null }
}
// fallback to first item if no non-reply found
const firstItem = items[0]
const description = firstItem.querySelector('description')?.textContent || ''
const link = firstItem.querySelector('link')?.textContent.trim()
+
+ // extract image from description html if available
+ const imgMatch = description.match(/
]+src="([^"]+)"/)
+ const image = imgMatch ? imgMatch[1] : null
+
let cleanText = sanitizeHtml(description, {
allowedTags: [],
allowedAttributes: {},
})?.trim()
// replace URLs with link emoji
cleanText = cleanText.replace(/https?:\/\/\S+/g, '🔗').trim()
- return { text: cleanText, url: link }
+
+ return { text: cleanText, url: link, image: showImage ? image : null }
}
// ========================================================================
@@ -192,16 +200,15 @@ export async function getLetterboxdActivity(config) {
const title = item.querySelector('title').textContent
const link = item.querySelector('link').textContent.trim()
- let text = title
+ let image = null
if (showImage) {
// Parse CDATA content as HTML to extract image
const description = item.querySelector('description').textContent
const imgMatch = description.match(/
]+src="([^"]+)"/)
- const image = imgMatch ? imgMatch[1] : null
- text = image ? `${title} ` : title
+ image = imgMatch ? imgMatch[1] : null
}
- return { text, url: link }
+ return { text: title, url: link, image }
}
// trakt episode history - requires TRAKT_SLURM variable (see readme for info)
@@ -216,10 +223,10 @@ export async function getTraktEpisode(config) {
const entry = dom.window.document.querySelector('entry')
const title = entry.querySelector('title').textContent
const link = entry.querySelector('link').getAttribute('href')
- const text = !showImage
- ? title
- : `${title} `
- return { text, url: link }
+ const image = showImage
+ ? `https://widgets.trakt.tv/users/${traktId}/watched/thumb@2x.jpg?type=episode&image_only=1`
+ : null
+ return { text: title, url: link, image }
}
// trakt movie history - requires TRAKT_SLURM variable (see readme for info)
@@ -234,10 +241,10 @@ export async function getTraktMovie(config) {
const entry = dom.window.document.querySelector('entry')
const title = entry.querySelector('title').textContent
const link = entry.querySelector('link').getAttribute('href')
- const text = !showImage
- ? title
- : `${title} `
- return { text, url: link }
+ const image = showImage
+ ? `https://widgets.trakt.tv/users/${traktId}/watched/thumb@2x.jpg?type=movie&image_only=1`
+ : null
+ return { text: title, url: link, image }
}
// ========================================================================