From 2165ce5bd37b290e865c8453dbc318a471f33773 Mon Sep 17 00:00:00 2001 From: dylan Date: Sun, 28 Dec 2025 22:18:27 +0000 Subject: [PATCH] updated README with support for new services --- README.md | 195 +++++++++++++++++++++++++++++++++++------------------- 1 file changed, 127 insertions(+), 68 deletions(-) diff --git a/README.md b/README.md index bd3ec9f..d2e666b 100644 --- a/README.md +++ b/README.md @@ -2,13 +2,13 @@ Automatically updates your omg.lol Now page with your latest activity. -> Fork of [melanie/now-updater](https://source.tube/melanie/now-updater) with added support for HTML output links, Mastodon, Last.fm, and dynamic URLs. +> Fork of [melanie/now-updater](https://source.tube/melanie/now-updater) with added support for HTML links, images/videos, Steam, Hardcover, some.pics, and simplified service configuration. Demo: [dylan.omg.lol/now](https://dylan.omg.lol/now) ## How It Works -Fetches content from RSS feeds, JSON feeds, and different services (Letterboxd, Trakt, Mastodon, Last.fm) and updates HTML or markdown links on your Now page. Runs every 3 hours via Forgejo Actions, only updating your page when changes are detected. +Fetches content from RSS feeds, JSON feeds, and different services (Letterboxd, Trakt, Last.fm, Steam, Hardcover, etc.) and updates HTML or markdown links on your Now page. Supports optional images and videos for services that provide them (These are... iffy so if something breaks it's probably this). Runs every 3 hours via Forgejo Actions, only updating your page when changes are detected. ### Example Your Now page links will be automatically updated from this: @@ -37,15 +37,14 @@ to this: [Pushed to repository](https://gitlab.com/username/project) ``` -**New in this fork**: Use service names as link text instead of URLs! Just write `servicename` and the script fills in both the text and URL. - ## Setup 1. Fork this repo 2. Enable Actions in repo settings 3. Add Actions variables: `OMGLOL_USERNAME` (your omg.lol username) -4. Add Actions secrets: `OMGLOL_KEY` (your API key), `TRAKT_SLURM` (optional, see [Trakt](#trakt) for details) -5. Add your sources in `config.js` +4. Add Actions secrets: `OMGLOL_KEY` (your API key) +5. Add optional secrets for services you want to use: `TRAKT_SLURM`, `STEAM_WEBAPI_KEY`, `HARDCOVER_API_KEY` +6. Activate your services in `services.js` by setting `isActive: true` For local development, copy `.env.example` to `.env` with your credentials. @@ -53,29 +52,34 @@ For local development, copy `.env.example` to `.env` with your credentials. **Now page template:** ```html -I wrote this: [tktk](https://your-blog.com) -I watched this: [tktk](trakt.tv/users/username) +I wrote this: blog +I watched this: letterboxd +I listened to: lastfm ``` -**config.js:** +**services.js:** ```js -export const linkFormat = 'markdown' - -export const items = [ +export const services = [ { id: 'blog', - regex: htmlLinkRegex('your-blog.com'), - getLatest: async () => getJsonFeedItemTitle('https://your-blog.com/feed.json'), + isActive: true, + feedUrl: 'https://your-blog.com/feed.json', + feedType: 'json', }, { id: 'letterboxd', - regex: htmlLinkRegex('letterboxd.com/username'), - getLatest: async () => getLetterboxdActivity('username', true), // with image + isActive: true, + userId: 'your-username', + feedUrlTemplate: 'https://letterboxd.com/{userId}/rss/', + feedType: 'letterboxd', + showImage: true, // optional: include movie posters }, { - id: 'trakt-movie', - regex: htmlLinkRegex('trakt.tv/users/username'), - getLatest: async () => getTraktMovie('username', 'your-trakt-id', false), // text only + id: 'lastfm', + isActive: true, + userId: 'your-username', + feedUrlTemplate: 'https://lfm.xiffy.nl/{userId}', + feedType: 'rss', }, ] ``` @@ -95,81 +99,124 @@ export const items = [ { id: 'gitlab', isActive: true, // just change this! - regex: htmlServiceLinkRegex('gitlab'), - feedUrl: 'https://gitlab.com/users/your-username/activity.atom', + userId: 'your-username', + feedUrlTemplate: 'https://gitlab.com/users/{userId}/activity.atom', feedType: 'atom', } ``` -That's it! No importing, no commenting/uncommenting. +The service `id` is used to match the link text in your Now page (e.g., `blog` matches `id: 'blog'`). If you need multiple instances of the same service just create separate entries in `services.js` with unique `id`s and matching link texts. Like so: + +```js + { + id: 'mastodon-personal', + isActive: false, + userId: 'dylan', + instance: 'social.lol', // your mastodon instance + feedUrlTemplate: 'https://{instance}/@{userId}.rss', + feedType: 'mastodon', + showImage: true, + }, + { + id: 'mastodon-work', + isActive: false, + userId: 'mrdylan', + instance: 'mastodon.instance', // your mastodon instance + feedUrlTemplate: 'https://{instance}/@{userId}.rss', + feedType: 'mastodon', + showImage: true, + }, +``` +Then you can have multiple Mastodon accounts on your Now page with different link texts: `[mastodon-personal](service-link)` and `[mastodon-work](service-link)`. ### Files -- **config.js** - Link format setting and filter logic (rarely needs editing) +- **config.js** - Link format setting (`html` or `markdown`) and filter logic - **services.js** - All available services with `isActive` flags (edit this to enable/disable services) -- **utils.js** - Generic feed handlers and special service logic +- **utils.js** - Generic feed handlers and service-specific logic ### Service Structure Each service has: -- `id`: identifier for logs +- `id`: Identifier that matches the link text in your Now page (e.g., `id: 'blog-1'` matches `blog-1`) - `isActive`: `true` to enable, `false` to disable -- `regex`: matches service name in your Now page -- `feedType`: Handler to use (`rss`, `atom`, `json`, or special handler name like `mastodon`) +- `feedType`: Handler to use (`rss`, `atom`, `json`, or special handler name like `letterboxd`, `steam`, `hardcover`) - `feedUrl`: Direct feed URL (use this for custom feeds without usernames) -- `feedUrlTemplate`: URL template with `{userId}` placeholder (use this for standard services) +- `feedUrlTemplate`: URL template with `{userId}` or `{instance}` placeholders - `userId`: Your username/ID (only needed with feedUrlTemplate) -- Extra params as needed (e.g., `instance`, `steamId`, `traktId`, `showImage`) +- `showImage`: Optional. Controls whether image/videos are included (defaults based on service) +- Extra params as needed (e.g., `instance` for federated services, `traktId` for Trakt widgets) -**Note**: Use either `feedUrl` (direct) OR `feedUrlTemplate` + `userId` (template). Both work! +Set `linkFormat` in config.js to `'html'` or `'markdown'` depending on your Now page format. -Set `linkFormat` in config.js to `'html'` or `'markdown'`. +### Image and Video Support -## Available Functions +Many services support optional images and videos: +- **Letterboxd**: Movie posters from CDATA descriptions +- **Trakt**: Episode/movie poster widgets (portrait orientation, change the URL from `poster` to `thumb` for landscape) +- **Hardcover**: Book cover images +- **Steam**: Game library posters +- **Mastodon**: Attached images and videos from `media:content` tags (iffy, may not always work) +- **some.pics**: Photo images from RSS CDATA -### Code Activity -- `getSourceTubeActivity(username)` - Forgejo activity on source.tube -- `getGitLabActivity(username)` - GitLab activity feed -- `getCodebergActivity(username)` - Codeberg activity feed +Control image inclusion with the `showImage` flag in your service config. Images are returned separately from text so you can control placement on your Now page. -### Content Creation -- `getYouTubeLatestVideo(channelId)` - Latest YouTube video (requires channel ID starting with "UC") -- `getVimeoLatestVideo(username)` - Latest Vimeo video -- `getTwitchLatestStream(channel)` - Latest Twitch stream/VOD (via TwitchRSS, no API key needed) +## Available Services -### Gaming -- `getBackloggdActivity(username, showImage)` - Backloggd game activity with optional cover images -- `getExophaseActivity(username, showImage)` - Multi-platform gaming achievements -- `getSteamRecentlyPlayed(steamId)` - Recently played Steam game (requires STEAM_WEBAPI_KEY) +All handlers now use a config object with consistent parameters. The `feedType` in services.js maps to these handlers. -### Books -- `getGoodreadsActivity(userId, showImage)` - Goodreads activity (requires numeric user ID, not username) -- `getHardcoverActivity(username)` - Currently reading books via GraphQL API +### Generic Feed Handlers +- `getRSSItemTitle(feedUrl)` - Standard RSS feeds +- `getAtomFeed(url)` - Standard Atom feeds +- `getJsonFeedItemTitle(feedUrl, showImage)` - JSON feeds with optional images + +### omg.lol Services +- `getSomePicsPost(feedUrl)` - some.pics photo posts with images extracted from CDATA ### Music -- `getListenBrainzScrobble(username)` - Latest music scrobble (open source Last.fm alternative) +- `getListenBrainzScrobble(config)` - ListenBrainz scrobbles (not tested, let me know!) + - Config: `{ feedUrl, userId }` +- For Last.fm, use generic RSS handler with `https://lfm.xiffy.nl/{userId}` ### Social Media -- `getPixelfedPost(instance, username)` - Latest Pixelfed post from federated instance -- `getBlueskyPost(handle)` - Latest Bluesky post (note: links not clickable in RSS) +- `getMastodonPost(config)` - Latest non-reply Mastodon post with optional images/videos + - Config: `{ feedUrl, showImage }` + - Extracts media from `media:content` tags and filters out replies -### General/Legacy -- `getRSSItemTitle(feedUrl)` - Standard RSS feeds -- `getJsonFeedItemTitle(feedUrl, showImage)` - JSON feeds -- `getLetterboxdActivity(username, showImage)` - Letterboxd activity -- `getTraktEpisode(username, id, showImage)` - Latest TV episode -- `getTraktMovie(username, id, showImage)` - Latest movie -- `getTraktEpisodeAndMovie(username, id, showImage)` - Latest episode and movie combined -- `getMastodonPost(feedUrl)` - Latest non-reply Mastodon post -- `getMalojaScrobble(url)` - Latest music scrobble from [maloja](https://github.com/krateng/maloja) +### Movies & TV +- `getLetterboxdActivity(config)` - Letterboxd activity with optional poster images + - Config: `{ feedUrl, showImage }` + - Extracts images from CDATA descriptions +- `getTraktEpisode(config)` - Latest TV episode with optional poster + - Config: `{ userId, traktId, showImage }` + - Requires `TRAKT_SLURM` environment variable + - Uses portrait poster widgets +- `getTraktMovie(config)` - Latest movie with optional poster + - Config: `{ userId, traktId, showImage }` + - Requires `TRAKT_SLURM` environment variable + - Uses portrait poster widgets + +### Books +- `getHardcoverActivity(config)` - Currently reading books with cover images + - Config: `{ userId, feedUrl }` + - Uses GraphQL API, requires `HARDCOVER_API_KEY` + - `userId` must be numeric user ID (not username) + +### Gaming +- `getSteamRecentlyPlayed(config)` - Recently played Steam game with library poster + - Config: `{ userId }` + - Requires `STEAM_WEBAPI_KEY` environment variable + - `userId` must be Steam ID 64 (convert at https://steamid.io/) + +### Code & Development +- `getSourceTubeActivity(config)` - Forgejo activity on source.tube + - Config: `{ feedUrl, userId }` + - Strips username prefix from activity descriptions (e.g., "dylan pushed to repository" becomes "pushed to repository") **Important Notes:** -- `showImage` (defaults to `true`) controls whether images/posters are included in the output. Set it to `false` to show text only. -- For Last.fm, use `getRSSItemTitle('https://lfm.xiffy.nl/your-username')` (via [lfm.xiffy.nl](https://lfm.xiffy.nl)) -- **YouTube** requires channel ID (not username), find it in your channel's page source or URL -- **Goodreads** requires numeric user ID (found in profile URL after `/user/show/`) -- **Steam** requires Steam ID 64 (convert at https://steamid.io/) -- **Pixelfed** requires instance domain and username (e.g., `pixelfed.social`, `username`) +- `showImage` controls whether images/videos are included in the response +- Images and videos are returned separately from text (as `{ text, url, image, video }`) +- Generic RSS/Atom/JSON handlers work with most standard feeds ## API Keys Setup @@ -179,19 +226,31 @@ To get your Trakt slurm key, follow these steps: 1. Go to your History page on Trakt: `https://trakt.tv/users/your-username/history` 2. There should be an RSS feed icon on the top right of the page. Click it. -3. The URL it shows will look something like this: `https://trakt.tv/users/crankle/history.atom?slurm=your-slurm-key` +3. The URL it shows will look something like this: `https://trakt.tv/users/username/history.atom?slurm=your-slurm-key` 4. Copy the `slurm` value from the URL and add it as a secret in your Actions settings named `TRAKT_SLURM`. +5. Add it to your `.env` file for local testing. ### Steam To get your Steam Web API key: 1. Visit https://steamcommunity.com/dev/apikey -2. Enter a domain name (can be localhost for personal use) +2. Enter a domain name (I used omg.lol, I don't know if that will cause me issues later) 3. Agree to the terms and get your API key -4. Add it to your `.env` file as `STEAM_WEBAPI_KEY` or to Actions secrets +4. Add it to your `.env` as `STEAM_WEBAPI_KEY` and to Actions secrets 5. Find your Steam ID 64 at https://steamid.io/ (enter your profile URL) +**Note**: The Steam handler uses the GetOwnedGames API endpoint sorted by `rtime_last_played`, which has no time limit. GetRecentlyPlayedGames can be used too, but it only shows anything played in the last 14 days which may be limiting. + +### Hardcover + +To get your Hardcover API key: + +1. Visit https://hardcover.app/account/api (Make sure you're logged in) +2. Find the authorisation header token section +3. **Important**: The token shown will include "Bearer " at the beginning - do not include this prefix when adding it (Note the space after "Bearer", that needs to be removed too) +4. Add the token to your `.env` file as `HARDCOVER_API_KEY` and to Actions secrets + ## Credits Original project by [melanie kat](https://source.tube/melanie/now-updater). Without her work, this fork would not exist.