updated to include image extraction and separate image urls
This commit is contained in:
parent
acdb9ff8d7
commit
689079cab4
3 changed files with 49 additions and 26 deletions
17
index.js
17
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(`(<img[^>]+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)
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
},
|
||||
|
||||
// ========================================================================
|
||||
|
|
|
|||
51
utils.js
51
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(/<img[^>]+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(/<img[^>]+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(/<img[^>]+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 }
|
||||
}
|
||||
|
||||
// ========================================================================
|
||||
|
|
|
|||
Loading…
Reference in a new issue