Compare commits
No commits in common. "main" and "update/new-services" have entirely different histories.
main
...
update/new
6 changed files with 46 additions and 65 deletions
9
.env.example
Normal file
9
.env.example
Normal file
|
|
@ -0,0 +1,9 @@
|
||||||
|
OMGLOL_KEY=
|
||||||
|
OMGLOL_USERNAME=melanie
|
||||||
|
TRAKT_SLURM=
|
||||||
|
|
||||||
|
# optional - only needed if using steam service
|
||||||
|
STEAM_WEBAPI_KEY=
|
||||||
|
|
||||||
|
# optional - only needed if using hardcover service
|
||||||
|
HARDCOVER_API_KEY=
|
||||||
12
README.md
12
README.md
|
|
@ -10,8 +10,6 @@ Demo: [dylan.omg.lol/now](https://dylan.omg.lol/now)
|
||||||
|
|
||||||
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.
|
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.
|
||||||
|
|
||||||
Images are matched using a `data-service` attribute on the img tag, which allows them to be updated repeatedly even after the initial replacement.
|
|
||||||
|
|
||||||
### Example
|
### Example
|
||||||
Your Now page links will be automatically updated from this:
|
Your Now page links will be automatically updated from this:
|
||||||
|
|
||||||
|
|
@ -56,7 +54,6 @@ For local development, copy `.env.example` to `.env` with your credentials.
|
||||||
```html
|
```html
|
||||||
I wrote this: <a href="https://your-blog.com">blog</a>
|
I wrote this: <a href="https://your-blog.com">blog</a>
|
||||||
I watched this: <a href="https://letterboxd.com/username">letterboxd</a>
|
I watched this: <a href="https://letterboxd.com/username">letterboxd</a>
|
||||||
<img data-service="letterboxd" src="letterboxd-image" style="max-width: 120px;">
|
|
||||||
I listened to: <a href="https://www.last.fm/user/username">lastfm</a>
|
I listened to: <a href="https://www.last.fm/user/username">lastfm</a>
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
@ -164,15 +161,6 @@ Many services support optional images and videos:
|
||||||
|
|
||||||
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.
|
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.
|
||||||
|
|
||||||
To use images, your img tags must include a `data-service` attribute matching the service `id` from services.js. For example:
|
|
||||||
|
|
||||||
```html
|
|
||||||
<img data-service="letterboxd" src="letterboxd-image" style="max-width: 120px;">
|
|
||||||
<img data-service="steam" src="steam-image" style="max-width: 120px;">
|
|
||||||
```
|
|
||||||
|
|
||||||
The `src` attribute can start with a placeholder (like `letterboxd-image`) or an existing URL - the updater will replace it either way as long as the `data-service` attribute is present.
|
|
||||||
|
|
||||||
## Available Services
|
## Available Services
|
||||||
|
|
||||||
All handlers now use a config object with consistent parameters. The `feedType` in services.js maps to these handlers.
|
All handlers now use a config object with consistent parameters. The `feedType` in services.js maps to these handlers.
|
||||||
|
|
|
||||||
24
index.js
24
index.js
|
|
@ -96,7 +96,7 @@ export default async function now() {
|
||||||
if (latest.image) console.log(`${item.id} Image: ${latest.image}`)
|
if (latest.image) console.log(`${item.id} Image: ${latest.image}`)
|
||||||
if (latest.video) console.log(`${item.id} Video: ${latest.video}`)
|
if (latest.video) console.log(`${item.id} Video: ${latest.video}`)
|
||||||
|
|
||||||
// apply markdown escaping only for markdown links
|
// Apply markdown escaping only for markdown links
|
||||||
const displayText =
|
const displayText =
|
||||||
linkFormat === 'html'
|
linkFormat === 'html'
|
||||||
? latest.text
|
? latest.text
|
||||||
|
|
@ -109,23 +109,13 @@ export default async function now() {
|
||||||
? htmlServiceLinkRegex(item.id)
|
? htmlServiceLinkRegex(item.id)
|
||||||
: markdownServiceLinkRegex(item.id)
|
: markdownServiceLinkRegex(item.id)
|
||||||
|
|
||||||
console.log(`\nDEBUG: Testing regex for ${item.id}`)
|
newNow = newNow.replace(regex, (match, openTag, closeTag) => {
|
||||||
console.log(`Regex: ${regex}`)
|
// Replace href in opening tag
|
||||||
const matched = regex.test(newNow)
|
|
||||||
console.log(`Regex match found: ${matched}`)
|
|
||||||
|
|
||||||
newNow = newNow.replace(regex, (match, openTag, oldText, closeTag) => {
|
|
||||||
console.log(`DEBUG: Replacing match for ${item.id}`)
|
|
||||||
console.log(`Old match: ${match}`)
|
|
||||||
console.log(`Old text: ${oldText}`)
|
|
||||||
// replace href in opening tag
|
|
||||||
const updatedOpenTag = openTag.replace(
|
const updatedOpenTag = openTag.replace(
|
||||||
/href=["'][^"']*["']/,
|
/href=["'][^"']*["']/,
|
||||||
`href="${latest.url}"`,
|
`href="${latest.url}"`,
|
||||||
)
|
)
|
||||||
const result = `${updatedOpenTag}${displayText}${closeTag}`
|
return `${updatedOpenTag}${displayText}${closeTag}`
|
||||||
console.log(`New replacement: ${result}`)
|
|
||||||
return result
|
|
||||||
})
|
})
|
||||||
|
|
||||||
// replace image/video placeholders if available, otherwise remove tags
|
// replace image/video placeholders if available, otherwise remove tags
|
||||||
|
|
@ -175,15 +165,9 @@ export default async function now() {
|
||||||
}),
|
}),
|
||||||
)
|
)
|
||||||
|
|
||||||
console.log('\n=== FINAL COMPARISON ===')
|
|
||||||
console.log(`Original length: ${now.length}`)
|
|
||||||
console.log(`New length: ${newNow.length}`)
|
|
||||||
console.log(`Strings are equal: ${now === newNow}`)
|
|
||||||
|
|
||||||
if (now === newNow) {
|
if (now === newNow) {
|
||||||
console.log('\nNow page has no changes')
|
console.log('\nNow page has no changes')
|
||||||
} else {
|
} else {
|
||||||
console.log('\nChanges detected! Updating Now page...')
|
|
||||||
await setNow(newNow)
|
await setNow(newNow)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -2,15 +2,15 @@
|
||||||
<p>This page <em>should</em> update automatically with my latest activity.</p>
|
<p>This page <em>should</em> update automatically with my latest activity.</p>
|
||||||
|
|
||||||
<div style="display: flex; flex-direction: column; gap: 0.75rem;">
|
<div style="display: flex; flex-direction: column; gap: 0.75rem;">
|
||||||
<div style="background: rgba(166, 227, 161, 0.15); padding: 1rem; border: 4px solid #a6e3a1; color:white;text-align: left;"><div><i class="fa-brands fa-lastfm"></i> I listened to this<br><a data-service="lastfm" href="https://www.last.fm/user/lookathimthere" style="color: #a6e3a1 !important;">lastfm</a></div></div>
|
<div style="background: rgba(166, 227, 161, 0.15); padding: 1rem; border: 4px solid #a6e3a1; color:white;text-align: left;"><div><i class="fa-brands fa-lastfm"></i> I listened to this<br><a href="https://www.last.fm/user/lookathimthere" style="color: #a6e3a1 !important;">lastfm</a></div></div>
|
||||||
<div style="background: rgba(250, 179, 135, 0.15); padding: 1rem; border: 4px solid #fab387; color:white; display: flex; justify-content: space-between; align-items: center;"><div style="text-align: left;"><i class="fa-solid fa-tv"></i> I watched this episode<br><a data-service="trakt-episode" href="https://trakt.tv/episodes" style="color: #fab387 !important;">trakt-episode</a></div><img data-service="trakt-episode" src="trakt-episode-image" style="max-width: 120px; max-height: 120px; object-fit: cover; border-radius: 4px;"></div>
|
<div style="background: rgba(250, 179, 135, 0.15); padding: 1rem; border: 4px solid #fab387; color:white; display: flex; justify-content: space-between; align-items: center;"><div style="text-align: left;"><i class="fa-solid fa-tv"></i> I watched this episode<br><a href="https://trakt.tv/episodes" style="color: #fab387 !important;">trakt-episode</a></div><img src="trakt-episode-image" style="max-width: 120px; max-height: 120px; object-fit: cover; border-radius: 4px;"></div>
|
||||||
<div style="background: rgba(250, 179, 135, 0.15); padding: 1rem; border: 4px solid #fab387; color:white; display: flex; justify-content: space-between; align-items: center;"><div style="text-align: left;"><i class="fa-solid fa-film"></i> I watched this movie<br><a data-service="trakt-movie" href="https://trakt.tv/movies/" style="color: #fab387 !important;">trakt-movie</a></div><img data-service="trakt-movie" src="trakt-movie-image" style="max-width: 120px; max-height: 120px; object-fit: cover; border-radius: 4px;"></div>
|
<div style="background: rgba(250, 179, 135, 0.15); padding: 1rem; border: 4px solid #fab387; color:white; display: flex; justify-content: space-between; align-items: center;"><div style="text-align: left;"><i class="fa-solid fa-film"></i> I watched this movie<br><a href="https://trakt.tv/movies/" style="color: #fab387 !important;">trakt-movie</a></div><img src="trakt-movie-image" style="max-width: 120px; max-height: 120px; object-fit: cover; border-radius: 4px;"></div>
|
||||||
<div style="background: rgba(243, 139, 168, 0.15); padding: 1rem; border: 4px solid #f38ba8; color:white; display: flex; justify-content: space-between; align-items: center;"><div style="text-align: left;"><i class="fa-solid omg-icon omg-letterboxd"></i> I rated this<br><a data-service="letterboxd" href="https://letterboxd.com/STFUDonny" style="color: #f38ba8 !important;">letterboxd</a></div><img data-service="letterboxd" src="letterboxd-image" style="max-width: 120px; max-height: 120px; object-fit: cover; border-radius: 4px;"></div>
|
<div style="background: rgba(243, 139, 168, 0.15); padding: 1rem; border: 4px solid #f38ba8; color:white; display: flex; justify-content: space-between; align-items: center;"><div style="text-align: left;"><i class="fa-solid omg-icon omg-letterboxd"></i> I rated this<br><a href="https://letterboxd.com/STFUDonny" style="color: #f38ba8 !important;">letterboxd</a></div><img src="letterboxd-image" style="max-width: 120px; max-height: 120px; object-fit: cover; border-radius: 4px;"></div>
|
||||||
<div style="background: rgba(180, 190, 254, 0.15); padding: 1rem; border: 4px solid #b4befe; color:white; display: flex; justify-content: space-between; align-items: center;"><div style="text-align: left;"><i class="fa-solid fa-book"></i> I'm reading this<br><a data-service="hardcover" href="https://hardcover.app" style="color: #b4befe !important;">hardcover</a></div><img data-service="hardcover" src="hardcover-image" style="max-width: 120px; max-height: 120px; object-fit: cover; border-radius: 4px;"></div>
|
<div style="background: rgba(180, 190, 254, 0.15); padding: 1rem; border: 4px solid #b4befe; color:white; display: flex; justify-content: space-between; align-items: center;"><div style="text-align: left;"><i class="fa-solid fa-book"></i> I'm reading this<br><a href="https://hardcover.app" style="color: #b4befe !important;">hardcover</a></div><img src="hardcover-image" style="max-width: 120px; max-height: 120px; object-fit: cover; border-radius: 4px;"></div>
|
||||||
<div style="background: rgba(137, 180, 250, 0.15); padding: 1rem; border: 4px solid #89b4fa; color:white; display: flex; justify-content: space-between; align-items: center;"><div style="text-align: left;"><i class="fa-brands fa-steam"></i> I played this<br><a data-service="steam" href="https://store.steampowered.com" style="color: #89b4fa !important;">steam</a></div><img data-service="steam" src="steam-image" style="max-width: 120px; max-height: 120px; object-fit: cover; border-radius: 4px;"></div>
|
<div style="background: rgba(137, 180, 250, 0.15); padding: 1rem; border: 4px solid #89b4fa; color:white; display: flex; justify-content: space-between; align-items: center;"><div style="text-align: left;"><i class="fa-brands fa-steam"></i> I played this<br><a href="https://store.steampowered.com" style="color: #89b4fa !important;">steam</a></div><img src="steam-image" style="max-width: 120px; max-height: 120px; object-fit: cover; border-radius: 4px;"></div>
|
||||||
<div style="background: rgba(148, 226, 213, 0.15); padding: 1rem; border: 4px solid #94e2d5; color:white; display: flex; justify-content: space-between; align-items: center;"><div style="text-align: left;"><i class="fa-regular fa-images"></i> I shared this photo<br><a data-service="some.pics" href="https://dylan.some.pics" style="color: #94e2d5 !important;">some.pics</a></div><img data-service="some.pics" src="some.pics-image" style="max-width: 120px; max-height: 120px; object-fit: cover; border-radius: 4px;"></div>
|
<div style="background: rgba(148, 226, 213, 0.15); padding: 1rem; border: 4px solid #94e2d5; color:white; display: flex; justify-content: space-between; align-items: center;"><div style="text-align: left;"><i class="fa-regular fa-images"></i> I shared this photo<br><a href="https://dylan.some.pics" style="color: #94e2d5 !important;">some.pics</a></div><img src="some.pics-image" style="max-width: 120px; max-height: 120px; object-fit: cover; border-radius: 4px;"></div>
|
||||||
<div style="background: rgba(249, 226, 175, 0.15); padding: 1rem; border: 4px solid #f9e2af; color:white;text-align: left;"><i class="fa-regular fa-newspaper"></i>I wrote this<br><a data-service="weblog" href="https://dylan.weblog.lol" style="color: #f9e2af !important;">weblog</a></div>
|
<div style="background: rgba(249, 226, 175, 0.15); padding: 1rem; border: 4px solid #f9e2af; color:white;text-align: left;"><i class="fa-regular fa-newspaper"></i>I wrote this<br><a href="https://dylan.weblog.lol" style="color: #f9e2af !important;">weblog</a></div>
|
||||||
<div style="background: rgba(137, 220, 235, 0.15); padding: 1rem; border: 4px solid #89dceb; color:white;text-align: left;"><i class="fa-solid fa-code"></i> I pushed some (bad) code<br><a data-service="source.tube" href="https://source.tube/dylan" style="color: #89dceb !important;">source.tube</a></div>
|
<div style="background: rgba(137, 220, 235, 0.15); padding: 1rem; border: 4px solid #89dceb; color:white;text-align: left;"><i class="fa-solid fa-code"></i> I pushed some (bad) code<br><a href="https://source.tube/dylan" style="color: #89dceb !important;">source.tube</a></div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<h5>{last-updated}</h5>
|
<h5>{last-updated}</h5>
|
||||||
|
|
|
||||||
44
services.js
44
services.js
|
|
@ -7,14 +7,14 @@ export const services = [
|
||||||
// ========================================================================
|
// ========================================================================
|
||||||
{
|
{
|
||||||
id: 'weblog',
|
id: 'weblog',
|
||||||
isActive: false,
|
isActive: true,
|
||||||
userId: 'dylan', // your omg.lol username
|
userId: 'dylan', // your omg.lol username
|
||||||
feedUrlTemplate: 'https://{userId}.weblog.lol/feed.json',
|
feedUrlTemplate: 'https://{userId}.weblog.lol/feed.json',
|
||||||
feedType: 'json',
|
feedType: 'json',
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
id: 'some.pics',
|
id: 'some.pics',
|
||||||
isActive: false,
|
isActive: true,
|
||||||
userId: 'dylan', // your omg.lol username
|
userId: 'dylan', // your omg.lol username
|
||||||
feedUrlTemplate: 'https://{userId}.some.pics/rss',
|
feedUrlTemplate: 'https://{userId}.some.pics/rss',
|
||||||
feedType: 'some.pics',
|
feedType: 'some.pics',
|
||||||
|
|
@ -25,9 +25,9 @@ export const services = [
|
||||||
// ========================================================================
|
// ========================================================================
|
||||||
{
|
{
|
||||||
id: 'blog',
|
id: 'blog',
|
||||||
isActive: true,
|
isActive: false,
|
||||||
feedUrl: 'https://blog.agnes.love/feed/', // direct url to your blog's rss feed
|
feedUrl: 'https://your-blog.com/feed.xml', // direct url to your blog's rss feed
|
||||||
feedType: 'atom',
|
feedType: 'rss',
|
||||||
},
|
},
|
||||||
|
|
||||||
// ========================================================================
|
// ========================================================================
|
||||||
|
|
@ -36,7 +36,7 @@ export const services = [
|
||||||
{
|
{
|
||||||
id: 'lastfm',
|
id: 'lastfm',
|
||||||
isActive: true,
|
isActive: true,
|
||||||
userId: 'keegbovo', // your last.fm username
|
userId: 'lookathimthere', // your last.fm username
|
||||||
feedUrlTemplate: 'https://lfm.xiffy.nl/{userId}',
|
feedUrlTemplate: 'https://lfm.xiffy.nl/{userId}',
|
||||||
feedType: 'rss',
|
feedType: 'rss',
|
||||||
},
|
},
|
||||||
|
|
@ -59,11 +59,11 @@ export const services = [
|
||||||
// ========================================================================
|
// ========================================================================
|
||||||
{
|
{
|
||||||
id: 'mastodon',
|
id: 'mastodon',
|
||||||
isActive: true,
|
isActive: false,
|
||||||
userId: 'alien', // your mastodon username
|
userId: 'dylan', // your mastodon username
|
||||||
instance: 'lesbian.alien.dentist', // your mastodon instance
|
instance: 'social.lol', // your mastodon instance
|
||||||
feedUrlTemplate: 'lesbian.alien.dentist/@alien.atom',
|
feedUrlTemplate: 'https://{instance}/@{userId}.rss',
|
||||||
feedType: 'atom',
|
feedType: 'mastodon',
|
||||||
showImage: true,
|
showImage: true,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
|
@ -76,9 +76,9 @@ export const services = [
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
id: 'bluesky',
|
id: 'bluesky',
|
||||||
isActive: true,
|
isActive: false,
|
||||||
userId: 'agnes.love', // your bluesky handle
|
userId: 'your-handle.bsky.social', // your bluesky handle
|
||||||
feedUrlTemplate: 'https://bsky.app/profile/agnes.love/rss',
|
feedUrlTemplate: 'https://bsky.app/profile/{userId}/rss',
|
||||||
feedType: 'rss',
|
feedType: 'rss',
|
||||||
},
|
},
|
||||||
|
|
||||||
|
|
@ -87,7 +87,7 @@ export const services = [
|
||||||
// ========================================================================
|
// ========================================================================
|
||||||
{
|
{
|
||||||
id: 'letterboxd',
|
id: 'letterboxd',
|
||||||
isActive: false,
|
isActive: true,
|
||||||
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',
|
||||||
|
|
@ -95,7 +95,7 @@ export const services = [
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
id: 'trakt-episode',
|
id: 'trakt-episode',
|
||||||
isActive: false,
|
isActive: true,
|
||||||
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',
|
||||||
|
|
@ -103,7 +103,7 @@ export const services = [
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
id: 'trakt-movie',
|
id: 'trakt-movie',
|
||||||
isActive: false,
|
isActive: true,
|
||||||
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',
|
||||||
|
|
@ -115,7 +115,7 @@ export const services = [
|
||||||
// ========================================================================
|
// ========================================================================
|
||||||
{
|
{
|
||||||
id: 'hardcover',
|
id: 'hardcover',
|
||||||
isActive: false,
|
isActive: true,
|
||||||
userId: '62036', // your hardcover user ID (find in your API token or profile URL)
|
userId: '62036', // your hardcover user ID (find in your API token or profile URL)
|
||||||
feedUrl: 'https://api.hardcover.app/v1/graphql',
|
feedUrl: 'https://api.hardcover.app/v1/graphql',
|
||||||
feedType: 'hardcover',
|
feedType: 'hardcover',
|
||||||
|
|
@ -123,8 +123,8 @@ export const services = [
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
id: 'storygraph',
|
id: 'storygraph',
|
||||||
isActive: true,
|
isActive: false,
|
||||||
userId: 'telescopefish', // your storygraph username
|
userId: 'your-username', // your storygraph username
|
||||||
feedUrlTemplate: 'https://app.thestorygraph.com/profile/{userId}.rss',
|
feedUrlTemplate: 'https://app.thestorygraph.com/profile/{userId}.rss',
|
||||||
feedType: 'rss',
|
feedType: 'rss',
|
||||||
},
|
},
|
||||||
|
|
@ -141,7 +141,7 @@ export const services = [
|
||||||
// ========================================================================
|
// ========================================================================
|
||||||
{
|
{
|
||||||
id: 'steam',
|
id: 'steam',
|
||||||
isActive: false,
|
isActive: true,
|
||||||
userId: '76561198022952207', // your steam ID 64 (not username) - convert at steamid.io
|
userId: '76561198022952207', // your steam ID 64 (not username) - convert at steamid.io
|
||||||
feedType: 'steam',
|
feedType: 'steam',
|
||||||
},
|
},
|
||||||
|
|
@ -151,7 +151,7 @@ export const services = [
|
||||||
// ========================================================================
|
// ========================================================================
|
||||||
{
|
{
|
||||||
id: 'source.tube',
|
id: 'source.tube',
|
||||||
isActive: false,
|
isActive: true,
|
||||||
userId: 'dylan', // your source.tube username
|
userId: 'dylan', // your source.tube username
|
||||||
feedUrlTemplate: 'https://source.tube/{userId}.rss',
|
feedUrlTemplate: 'https://source.tube/{userId}.rss',
|
||||||
feedType: 'source.tube',
|
feedType: 'source.tube',
|
||||||
|
|
|
||||||
4
utils.js
4
utils.js
|
|
@ -6,11 +6,11 @@ import sanitizeHtml from 'sanitize-html'
|
||||||
// helper functions
|
// helper functions
|
||||||
// ========================================================================
|
// ========================================================================
|
||||||
|
|
||||||
// regex to match service by data-service attribute within an html anchor tag
|
// regex to match service name within an html anchor tag
|
||||||
// used when linkFormat is 'html' in config.js
|
// used when linkFormat is 'html' in config.js
|
||||||
export function htmlServiceLinkRegex(serviceName) {
|
export function htmlServiceLinkRegex(serviceName) {
|
||||||
return new RegExp(
|
return new RegExp(
|
||||||
`(<a[^>]*data-service=["']${serviceName}["'][^>]*>)([^<]*)(<\\/a>)`,
|
`(<a[^>]+href=["'][^"']*["'][^>]*>)${serviceName}(<\\/a>)`,
|
||||||
'i',
|
'i',
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue