trakt support

This commit is contained in:
Melanie Kat 2025-12-17 21:53:32 -08:00
parent 4d58fff75d
commit 911d851fb1
5 changed files with 68 additions and 47 deletions

View file

@ -1,2 +1,3 @@
OMGLOL_KEY= OMGLOL_KEY=
OMGLOL_USERNAME=melanie OMGLOL_USERNAME=melanie
TRAKT_SLURM=

View file

@ -23,3 +23,4 @@ jobs:
env: env:
OMGLOL_KEY: ${{ secrets.OMGLOL_KEY }} OMGLOL_KEY: ${{ secrets.OMGLOL_KEY }}
OMGLOL_USERNAME: ${{ vars.OMGLOL_USERNAME }} OMGLOL_USERNAME: ${{ vars.OMGLOL_USERNAME }}
TRAKT_SLURM: ${{ secrets.TRAKT_SLURM }}

View file

@ -21,7 +21,8 @@
}, },
"javascript": { "javascript": {
"formatter": { "formatter": {
"quoteStyle": "double" "quoteStyle": "single",
"semicolons": "asNeeded"
} }
}, },
"assist": { "assist": {

View file

@ -3,36 +3,43 @@ import {
getJsonFeedItemTitle, getJsonFeedItemTitle,
getLetterboxdActivity, getLetterboxdActivity,
getMalojaScrobble, getMalojaScrobble,
getTraktEpisode,
markdownLinkRegex, markdownLinkRegex,
} from "./utils.js"; } from './utils.js'
export const items = [ export const items = [
{ {
id: "blog", id: 'blog',
regex: markdownLinkRegex("melkat.blog"), regex: markdownLinkRegex('melkat.blog'),
getLatest: async () => getLatest: async () =>
getJsonFeedItemTitle("https://melkat.blog/feed.json"), getJsonFeedItemTitle('https://melkat.blog/feed.json'),
}, },
{ {
id: "pics", id: 'pics',
regex: markdownLinkRegex("melkat.pics"), regex: markdownLinkRegex('melkat.pics'),
getLatest: async () => getLatest: async () =>
getJsonFeedItemTitle("https://melkat.pics/feed.json"), getJsonFeedItemTitle('https://melkat.pics/feed.json'),
}, },
{ {
id: "lol", id: 'lol',
regex: markdownLinkRegex("melkat.lol"), regex: markdownLinkRegex('melkat.lol'),
getLatest: async () => getLatest: async () =>
getJsonFeedItemContent("https://melkat.lol/feed.json"), getJsonFeedItemContent('https://melkat.lol/feed.json'),
}, },
{ {
id: "maloja", id: 'maloja',
regex: markdownLinkRegex("scrobbles.melkat.dev"), regex: markdownLinkRegex('scrobbles.melkat.dev'),
getLatest: async () => getMalojaScrobble("https://scrobbles.melkat.dev"), getLatest: async () => getMalojaScrobble('https://scrobbles.melkat.dev'),
}, },
{ {
id: "letterboxd", id: 'letterboxd',
regex: markdownLinkRegex("letterboxd.com/zicklepop"), regex: markdownLinkRegex('letterboxd.com/zicklepop'),
getLatest: async () => getLetterboxdActivity("zicklepop"), getLatest: async () => getLetterboxdActivity('zicklepop'),
}, },
]; {
id: 'trakt',
regex: markdownLinkRegex('trakt.tv/users/zicklepop'),
getLatest: async () =>
getTraktEpisode('zicklepop', 'd0a982626d7793b5cf1857a2128277cc'),
},
]

View file

@ -1,51 +1,62 @@
import { JSDOM } from "jsdom"; import 'dotenv/config'
import sanitizeHtml from "sanitize-html"; import { JSDOM } from 'jsdom'
import sanitizeHtml from 'sanitize-html'
export function markdownLinkRegex(url) { export function markdownLinkRegex(url) {
return new RegExp( return new RegExp(
`(\\[).*?(\\]\\(https:\\/\\/${url.replaceAll(".", "\\.")}\\))`, `(\\[).*?(\\]\\(https:\\/\\/${url.replaceAll('.', '\\.')}\\))`,
"i", 'i',
); )
} }
export async function getJsonFeedItemTitle(feedUrl) { export async function getJsonFeedItemTitle(feedUrl) {
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 } = post; const { title, image } = post
return image ? `${title} ![${title}](${image})` : title; return image ? `${title} ![${title}](${image})` : title
} }
export async function getJsonFeedItemContent(feedUrl) { export async function getJsonFeedItemContent(feedUrl) {
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 { content_html, image } = post; const { content_html, image } = post
const title = sanitizeHtml(content_html, { const title = sanitizeHtml(content_html, {
allowedTags: [], allowedTags: [],
allowedAttributes: {}, allowedAttributes: {},
})?.trim(); })?.trim()
return image ? `${title} ![${title}](${image})` : title; return image ? `${title} ![${title}](${image})` : title
} }
export async function getMalojaScrobble(malojaUrl) { export async function getMalojaScrobble(malojaUrl) {
const res = await fetch(`${malojaUrl}/apis/mlj_1/scrobbles?perpage=1`); const res = await fetch(`${malojaUrl}/apis/mlj_1/scrobbles?perpage=1`)
const data = await res.json(); const data = await res.json()
const scrobble = data.list[0]; const scrobble = data.list[0]
const { const {
title, title,
album: { artists }, album: { artists },
} = scrobble.track; } = scrobble.track
return `${title}<br />by ${artists.join(", ")}`; return `${title}<br />by ${artists.join(', ')}`
} }
export async function getLetterboxdActivity(username) { export async function getLetterboxdActivity(username) {
const res = await fetch(`https://letterboxd.com/${username}/rss/`); const res = await fetch(`https://letterboxd.com/${username}/rss/`)
const data = await res.text(); const data = await res.text()
const dom = new JSDOM(data); const dom = new JSDOM(data)
const item = dom.window.document.querySelector('item')
const item = dom.window.document.querySelector("item"); const title = item.querySelector('title').textContent
const title = item.querySelector("title").textContent; const image = item.querySelector('description > img').src
const image = item.querySelector("description > img").src; return `${title} ![${title}](${image})`
return `${title} ![${title}](${image})`; }
export async function getTraktEpisode(username, id) {
const res = await fetch(
`https://trakt.tv/users/${username}/history/episodes/added/asc.atom?slurm=${process.env.TRAKT_SLURM}`,
)
const data = await res.text()
const dom = new JSDOM(data)
const entry = dom.window.document.querySelector('entry')
const title = entry.querySelector('title').textContent
return `${title} ![${title}](https://widgets.trakt.tv/users/${id}/watched/thumb@2x.jpg?type=episode&image_only=1)`
} }