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
|
// 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,
|
item.feedType,
|
||||||
)
|
)
|
||||||
? feedUrl
|
? feedUrl
|
||||||
|
|
@ -109,6 +109,21 @@ export default async function now() {
|
||||||
)
|
)
|
||||||
return `${updatedOpenTag}${displayText}${closeTag}`
|
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) {
|
} catch (e) {
|
||||||
console.warn(`⚠️ Failed to fetch ${item.id}`, e)
|
console.warn(`⚠️ Failed to fetch ${item.id}`, e)
|
||||||
|
|
|
||||||
|
|
@ -64,6 +64,7 @@ export const services = [
|
||||||
instance: 'social.lol', // your mastodon instance
|
instance: 'social.lol', // your mastodon instance
|
||||||
feedUrlTemplate: 'https://{instance}/@{userId}.rss',
|
feedUrlTemplate: 'https://{instance}/@{userId}.rss',
|
||||||
feedType: 'mastodon',
|
feedType: 'mastodon',
|
||||||
|
showImage: false,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
id: 'pixelfed',
|
id: 'pixelfed',
|
||||||
|
|
@ -90,7 +91,7 @@ export const services = [
|
||||||
userId: 'stfudonny', // your letterboxd username
|
userId: 'stfudonny', // your letterboxd username
|
||||||
feedUrlTemplate: 'https://letterboxd.com/{userId}/rss/',
|
feedUrlTemplate: 'https://letterboxd.com/{userId}/rss/',
|
||||||
feedType: 'letterboxd',
|
feedType: 'letterboxd',
|
||||||
showImage: false,
|
showImage: true,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
id: 'trakt-episode',
|
id: 'trakt-episode',
|
||||||
|
|
@ -98,7 +99,7 @@ export const services = [
|
||||||
userId: 'crankle', // your trakt username
|
userId: 'crankle', // your trakt username
|
||||||
traktId: '78e1e87b446901f7e4f0883dd4995cec', // your trakt ID
|
traktId: '78e1e87b446901f7e4f0883dd4995cec', // your trakt ID
|
||||||
feedType: 'trakt-episode',
|
feedType: 'trakt-episode',
|
||||||
showImage: false,
|
showImage: true,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
id: 'trakt-movie',
|
id: 'trakt-movie',
|
||||||
|
|
@ -106,7 +107,7 @@ export const services = [
|
||||||
userId: 'crankle', // your trakt username
|
userId: 'crankle', // your trakt username
|
||||||
traktId: '78e1e87b446901f7e4f0883dd4995cec', // your trakt ID
|
traktId: '78e1e87b446901f7e4f0883dd4995cec', // your trakt ID
|
||||||
feedType: 'trakt-movie',
|
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
|
// 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) {
|
export async function getJsonFeedItemTitle(feedUrl, showImage = true) {
|
||||||
const res = await fetch(feedUrl)
|
const res = await fetch(feedUrl)
|
||||||
const data = await res.json()
|
const data = await res.json()
|
||||||
const post = data.items[0]
|
const post = data.items[0]
|
||||||
const { title, image, url } = post
|
const { title, image, url } = post
|
||||||
const text = !showImage
|
return { text: title, url, image: showImage ? image : null }
|
||||||
? title
|
|
||||||
: image
|
|
||||||
? `${title} `
|
|
||||||
: title
|
|
||||||
return { text, url }
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// ========================================================================
|
// ========================================================================
|
||||||
|
|
@ -133,7 +128,10 @@ export async function getMalojaScrobble(malojaUrl) {
|
||||||
|
|
||||||
// mastodon rss feed parser - filters out replies (posts starting with @)
|
// mastodon rss feed parser - filters out replies (posts starting with @)
|
||||||
// also replaces urls with 🔗 emoji to keep things tidy
|
// 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 res = await fetch(feedUrl)
|
||||||
const data = await res.text()
|
const data = await res.text()
|
||||||
const dom = new JSDOM(data, { contentType: 'text/xml' })
|
const dom = new JSDOM(data, { contentType: 'text/xml' })
|
||||||
|
|
@ -152,6 +150,10 @@ export async function getMastodonPost(feedUrl) {
|
||||||
|
|
||||||
const link = item.querySelector('link')?.textContent.trim()
|
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
|
// use description as the text, stripping HTML
|
||||||
let cleanText = sanitizeHtml(description, {
|
let cleanText = sanitizeHtml(description, {
|
||||||
allowedTags: [],
|
allowedTags: [],
|
||||||
|
|
@ -161,20 +163,26 @@ export async function getMastodonPost(feedUrl) {
|
||||||
// replace URLs with a link emoji
|
// replace URLs with a link emoji
|
||||||
cleanText = cleanText.replace(/https?:\/\/\S+/g, '🔗').trim()
|
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
|
// fallback to first item if no non-reply found
|
||||||
const firstItem = items[0]
|
const firstItem = items[0]
|
||||||
const description = firstItem.querySelector('description')?.textContent || ''
|
const description = firstItem.querySelector('description')?.textContent || ''
|
||||||
const link = firstItem.querySelector('link')?.textContent.trim()
|
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, {
|
let cleanText = sanitizeHtml(description, {
|
||||||
allowedTags: [],
|
allowedTags: [],
|
||||||
allowedAttributes: {},
|
allowedAttributes: {},
|
||||||
})?.trim()
|
})?.trim()
|
||||||
// replace URLs with link emoji
|
// replace URLs with link emoji
|
||||||
cleanText = cleanText.replace(/https?:\/\/\S+/g, '🔗').trim()
|
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 title = item.querySelector('title').textContent
|
||||||
const link = item.querySelector('link').textContent.trim()
|
const link = item.querySelector('link').textContent.trim()
|
||||||
|
|
||||||
let text = title
|
let image = null
|
||||||
if (showImage) {
|
if (showImage) {
|
||||||
// Parse CDATA content as HTML to extract image
|
// Parse CDATA content as HTML to extract image
|
||||||
const description = item.querySelector('description').textContent
|
const description = item.querySelector('description').textContent
|
||||||
const imgMatch = description.match(/<img[^>]+src="([^"]+)"/)
|
const imgMatch = description.match(/<img[^>]+src="([^"]+)"/)
|
||||||
const image = imgMatch ? imgMatch[1] : null
|
image = imgMatch ? imgMatch[1] : null
|
||||||
text = image ? `${title} ` : title
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return { text, url: link }
|
return { text: title, url: link, image }
|
||||||
}
|
}
|
||||||
|
|
||||||
// trakt episode history - requires TRAKT_SLURM variable (see readme for info)
|
// 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 entry = dom.window.document.querySelector('entry')
|
||||||
const title = entry.querySelector('title').textContent
|
const title = entry.querySelector('title').textContent
|
||||||
const link = entry.querySelector('link').getAttribute('href')
|
const link = entry.querySelector('link').getAttribute('href')
|
||||||
const text = !showImage
|
const image = showImage
|
||||||
? title
|
? `https://widgets.trakt.tv/users/${traktId}/watched/thumb@2x.jpg?type=episode&image_only=1`
|
||||||
: `${title} `
|
: null
|
||||||
return { text, url: link }
|
return { text: title, url: link, image }
|
||||||
}
|
}
|
||||||
|
|
||||||
// trakt movie history - requires TRAKT_SLURM variable (see readme for info)
|
// 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 entry = dom.window.document.querySelector('entry')
|
||||||
const title = entry.querySelector('title').textContent
|
const title = entry.querySelector('title').textContent
|
||||||
const link = entry.querySelector('link').getAttribute('href')
|
const link = entry.querySelector('link').getAttribute('href')
|
||||||
const text = !showImage
|
const image = showImage
|
||||||
? title
|
? `https://widgets.trakt.tv/users/${traktId}/watched/thumb@2x.jpg?type=movie&image_only=1`
|
||||||
: `${title} `
|
: null
|
||||||
return { text, url: link }
|
return { text: title, url: link, image }
|
||||||
}
|
}
|
||||||
|
|
||||||
// ========================================================================
|
// ========================================================================
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue