Add RSS plugin (#192)
This commit is contained in:
19
package-lock.json
generated
19
package-lock.json
generated
@@ -26,6 +26,7 @@
|
|||||||
"open-graph-scraper": "^4.7.1",
|
"open-graph-scraper": "^4.7.1",
|
||||||
"prismjs": "^1.23.0",
|
"prismjs": "^1.23.0",
|
||||||
"puppeteer": "^8.0.0",
|
"puppeteer": "^8.0.0",
|
||||||
|
"rss-parser": "^3.12.0",
|
||||||
"simple-git": "^2.36.0",
|
"simple-git": "^2.36.0",
|
||||||
"svgo": "^2.2.0",
|
"svgo": "^2.2.0",
|
||||||
"twemoji-parser": "^13.0.0",
|
"twemoji-parser": "^13.0.0",
|
||||||
@@ -9475,6 +9476,15 @@
|
|||||||
"rimraf": "bin.js"
|
"rimraf": "bin.js"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/rss-parser": {
|
||||||
|
"version": "3.12.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/rss-parser/-/rss-parser-3.12.0.tgz",
|
||||||
|
"integrity": "sha512-aqD3E8iavcCdkhVxNDIdg1nkBI17jgqF+9OqPS1orwNaOgySdpvq6B+DoONLhzjzwV8mWg37sb60e4bmLK117A==",
|
||||||
|
"dependencies": {
|
||||||
|
"entities": "^2.0.3",
|
||||||
|
"xml2js": "^0.4.19"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/rsvp": {
|
"node_modules/rsvp": {
|
||||||
"version": "4.8.5",
|
"version": "4.8.5",
|
||||||
"resolved": "https://registry.npmjs.org/rsvp/-/rsvp-4.8.5.tgz",
|
"resolved": "https://registry.npmjs.org/rsvp/-/rsvp-4.8.5.tgz",
|
||||||
@@ -19408,6 +19418,15 @@
|
|||||||
"glob": "^7.1.3"
|
"glob": "^7.1.3"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"rss-parser": {
|
||||||
|
"version": "3.12.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/rss-parser/-/rss-parser-3.12.0.tgz",
|
||||||
|
"integrity": "sha512-aqD3E8iavcCdkhVxNDIdg1nkBI17jgqF+9OqPS1orwNaOgySdpvq6B+DoONLhzjzwV8mWg37sb60e4bmLK117A==",
|
||||||
|
"requires": {
|
||||||
|
"entities": "^2.0.3",
|
||||||
|
"xml2js": "^0.4.19"
|
||||||
|
}
|
||||||
|
},
|
||||||
"rsvp": {
|
"rsvp": {
|
||||||
"version": "4.8.5",
|
"version": "4.8.5",
|
||||||
"resolved": "https://registry.npmjs.org/rsvp/-/rsvp-4.8.5.tgz",
|
"resolved": "https://registry.npmjs.org/rsvp/-/rsvp-4.8.5.tgz",
|
||||||
|
|||||||
@@ -40,6 +40,7 @@
|
|||||||
"open-graph-scraper": "^4.7.1",
|
"open-graph-scraper": "^4.7.1",
|
||||||
"prismjs": "^1.23.0",
|
"prismjs": "^1.23.0",
|
||||||
"puppeteer": "^8.0.0",
|
"puppeteer": "^8.0.0",
|
||||||
|
"rss-parser": "^3.12.0",
|
||||||
"simple-git": "^2.36.0",
|
"simple-git": "^2.36.0",
|
||||||
"svgo": "^2.2.0",
|
"svgo": "^2.2.0",
|
||||||
"twemoji-parser": "^13.0.0",
|
"twemoji-parser": "^13.0.0",
|
||||||
|
|||||||
@@ -11,9 +11,10 @@
|
|||||||
import twemojis from "twemoji-parser"
|
import twemojis from "twemoji-parser"
|
||||||
import jimp from "jimp"
|
import jimp from "jimp"
|
||||||
import opengraph from "open-graph-scraper"
|
import opengraph from "open-graph-scraper"
|
||||||
|
import rss from "rss-parser"
|
||||||
|
|
||||||
//Exports
|
//Exports
|
||||||
export {fs, os, paths, url, util, processes, axios, puppeteer, git, opengraph}
|
export {fs, os, paths, url, util, processes, axios, puppeteer, git, opengraph, rss}
|
||||||
|
|
||||||
/**Returns module __dirname */
|
/**Returns module __dirname */
|
||||||
export function __module(module) {
|
export function __module(module) {
|
||||||
|
|||||||
22
source/app/mocks/api/axios/get/rss.mjs
Normal file
22
source/app/mocks/api/axios/get/rss.mjs
Normal file
@@ -0,0 +1,22 @@
|
|||||||
|
/**Mocked data */
|
||||||
|
export default function({faker, url, options, login = faker.internet.userName()}) {
|
||||||
|
//Stackoverflow api
|
||||||
|
if (/^https:..example.org.rss$/.test(url)) {
|
||||||
|
console.debug(`metrics/compute/mocks > mocking rss feed result > ${url}`)
|
||||||
|
return ({
|
||||||
|
status:200,
|
||||||
|
data:{
|
||||||
|
items:new Array(30).fill(null).map(_ => ({
|
||||||
|
title:faker.lorem.sentence(),
|
||||||
|
link:faker.internet.url(),
|
||||||
|
content:faker.lorem.paragraphs(),
|
||||||
|
contentSnippet:faker.lorem.paragraph(),
|
||||||
|
isoDate:faker.date.recent(),
|
||||||
|
})),
|
||||||
|
title:faker.lorem.sentence(),
|
||||||
|
description:faker.lorem.paragraph(),
|
||||||
|
link:url,
|
||||||
|
},
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -230,6 +230,18 @@
|
|||||||
favorites:distribution(7).map((value, index, array) => ({name:faker.lorem.word(), color:faker.internet.color(), value, size:faker.random.number(1000000), x:array.slice(0, index).reduce((a, b) => a + b, 0)}))
|
favorites:distribution(7).map((value, index, array) => ({name:faker.lorem.word(), color:faker.internet.color(), value, size:faker.random.number(1000000), x:array.slice(0, index).reduce((a, b) => a + b, 0)}))
|
||||||
}
|
}
|
||||||
}) : null),
|
}) : null),
|
||||||
|
//Languages
|
||||||
|
...(set.plugins.enabled.rss ? ({
|
||||||
|
rss:{
|
||||||
|
source:faker.lorem.words(),
|
||||||
|
description:faker.lorem.paragraph(),
|
||||||
|
link:options["rss.source"],
|
||||||
|
feed:new Array(Number(options["rss.limit"])).fill(null).map(_ => ({
|
||||||
|
title:faker.lorem.sentence(),
|
||||||
|
date:faker.date.recent()
|
||||||
|
})),
|
||||||
|
}
|
||||||
|
}) : null),
|
||||||
//Habits
|
//Habits
|
||||||
...(set.plugins.enabled.habits ? ({
|
...(set.plugins.enabled.habits ? ({
|
||||||
habits:{
|
habits:{
|
||||||
|
|||||||
23
source/plugins/rss/README.md
Normal file
23
source/plugins/rss/README.md
Normal file
@@ -0,0 +1,23 @@
|
|||||||
|
### 🗼 Rss feed
|
||||||
|
|
||||||
|
The *rss* plugin displays items from a specified RSS feed.
|
||||||
|
|
||||||
|
<table>
|
||||||
|
<td align="center">
|
||||||
|
<img src="https://github.com/lowlighter/lowlighter/blob/master/metrics.plugin.rss.svg">
|
||||||
|
<img width="900" height="1" alt="">
|
||||||
|
</td>
|
||||||
|
</table>
|
||||||
|
|
||||||
|
#### ℹ️ Examples workflows
|
||||||
|
|
||||||
|
[➡️ Available options for this plugin](metadata.yml)
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
- uses: lowlighter/metrics@latest
|
||||||
|
with:
|
||||||
|
# ... other options
|
||||||
|
plugin_rss: yes
|
||||||
|
plugin_rss_source: https://news.ycombinator.com/rss # RSS feed
|
||||||
|
plugin_rss_limit: 6 # Limit to 6 items
|
||||||
|
```
|
||||||
34
source/plugins/rss/index.mjs
Normal file
34
source/plugins/rss/index.mjs
Normal file
@@ -0,0 +1,34 @@
|
|||||||
|
|
||||||
|
//Setup
|
||||||
|
export default async function({login, q, imports, data, account}, {enabled = false} = {}) {
|
||||||
|
//Plugin execution
|
||||||
|
try {
|
||||||
|
//Check if plugin is enabled and requirements are met
|
||||||
|
if ((!enabled)||(!q.rss))
|
||||||
|
return null
|
||||||
|
|
||||||
|
//Load inputs
|
||||||
|
let {source, limit} = imports.metadata.plugins.rss.inputs({data, account, q})
|
||||||
|
if (!source)
|
||||||
|
throw {error:{message:"A RSS feed is required"}}
|
||||||
|
|
||||||
|
//Load rss feed
|
||||||
|
const {title, description, link, items} = await (new imports.rss()).parseURL(source) //eslint-disable-line new-cap
|
||||||
|
const feed = items.map(({title, isoDate:date}) => ({title, date:new Date(date)}))
|
||||||
|
|
||||||
|
//Limit feed
|
||||||
|
if (limit > 0) {
|
||||||
|
console.debug(`metrics/compute/${login}/plugins > rss > keeping only ${limit} items`)
|
||||||
|
feed.splice(limit)
|
||||||
|
}
|
||||||
|
|
||||||
|
//Results
|
||||||
|
return {source:title, description, link, feed}
|
||||||
|
}
|
||||||
|
//Handle errors
|
||||||
|
catch (error) {
|
||||||
|
if (error.error?.message)
|
||||||
|
throw error
|
||||||
|
throw {error:{message:"An error occured", instance:error}}
|
||||||
|
}
|
||||||
|
}
|
||||||
30
source/plugins/rss/metadata.yml
Normal file
30
source/plugins/rss/metadata.yml
Normal file
@@ -0,0 +1,30 @@
|
|||||||
|
name: "🗼 Rss feed"
|
||||||
|
cost: N/A
|
||||||
|
categorie: social
|
||||||
|
index: 6.5
|
||||||
|
supports:
|
||||||
|
- user
|
||||||
|
- organization
|
||||||
|
- repository
|
||||||
|
inputs:
|
||||||
|
|
||||||
|
# Enable or disable plugin
|
||||||
|
plugin_rss:
|
||||||
|
description: Display RSS feed
|
||||||
|
type: boolean
|
||||||
|
default: no
|
||||||
|
|
||||||
|
# RSS feed source
|
||||||
|
plugin_rss_source:
|
||||||
|
description: RSS feed source
|
||||||
|
type: string
|
||||||
|
default: ""
|
||||||
|
|
||||||
|
# Number of items to display
|
||||||
|
# Set to 0 to disable limitations
|
||||||
|
plugin_rss_limit:
|
||||||
|
description: Maximum number of items to display
|
||||||
|
type: number
|
||||||
|
default: 4
|
||||||
|
min: 0
|
||||||
|
max: 30
|
||||||
6
source/plugins/rss/tests.yml
Normal file
6
source/plugins/rss/tests.yml
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
- name: Rss plugin (default)
|
||||||
|
uses: lowlighter/metrics@latest
|
||||||
|
with:
|
||||||
|
token: NOT_NEEDED
|
||||||
|
plugin_rss: yes
|
||||||
|
plugin_source: https://example.org/rss
|
||||||
@@ -13,6 +13,7 @@
|
|||||||
"music",
|
"music",
|
||||||
"nightscout",
|
"nightscout",
|
||||||
"posts",
|
"posts",
|
||||||
|
"rss",
|
||||||
"tweets",
|
"tweets",
|
||||||
"isocalendar",
|
"isocalendar",
|
||||||
"stars",
|
"stars",
|
||||||
|
|||||||
35
source/templates/classic/partials/rss.ejs
Normal file
35
source/templates/classic/partials/rss.ejs
Normal file
@@ -0,0 +1,35 @@
|
|||||||
|
<% if (plugins.rss) { %>
|
||||||
|
<section>
|
||||||
|
<h2 class="field">
|
||||||
|
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16" width="16" height="16"><path fill-rule="evenodd" d="M3.267 1.457c.3.286.312.76.026 1.06A6.475 6.475 0 001.5 7a6.472 6.472 0 001.793 4.483.75.75 0 01-1.086 1.034 8.89 8.89 0 01-.276-.304l.569-.49-.569.49A7.971 7.971 0 010 7c0-2.139.84-4.083 2.207-5.517a.75.75 0 011.06-.026zm9.466 0a.75.75 0 011.06.026A7.975 7.975 0 0116 7c0 2.139-.84 4.083-2.207 5.517a.75.75 0 11-1.086-1.034A6.475 6.475 0 0014.5 7a6.475 6.475 0 00-1.793-4.483.75.75 0 01.026-1.06zM8.75 8.582a1.75 1.75 0 10-1.5 0v5.668a.75.75 0 001.5 0V8.582zM5.331 4.736a.75.75 0 10-1.143-.972A4.983 4.983 0 003 7c0 1.227.443 2.352 1.177 3.222a.75.75 0 001.146-.967A3.483 3.483 0 014.5 7c0-.864.312-1.654.831-2.264zm6.492-.958a.75.75 0 00-1.146.967c.514.61.823 1.395.823 2.255 0 .86-.31 1.646-.823 2.255a.75.75 0 101.146.967A4.983 4.983 0 0013 7a4.983 4.983 0 00-1.177-3.222z"></path></svg>
|
||||||
|
<%= plugins.rss?.source ?? "" %> RSS feed
|
||||||
|
</h2>
|
||||||
|
<div class="row fill-width">
|
||||||
|
<section>
|
||||||
|
<% if (plugins.rss.error) { %>
|
||||||
|
<div class="field error">
|
||||||
|
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16" width="16" height="16"><path fill-rule="evenodd" d="M2.343 13.657A8 8 0 1113.657 2.343 8 8 0 012.343 13.657zM6.03 4.97a.75.75 0 00-1.06 1.06L6.94 8 4.97 9.97a.75.75 0 101.06 1.06L8 9.06l1.97 1.97a.75.75 0 101.06-1.06L9.06 8l1.97-1.97a.75.75 0 10-1.06-1.06L8 6.94 6.03 4.97z"></path></svg>
|
||||||
|
<%= plugins.rss.error.message %>
|
||||||
|
</div>
|
||||||
|
<% } else { %>
|
||||||
|
<% if (plugins.rss.feed.length) { %>
|
||||||
|
<% for (const {title, date} of plugins.rss.feed) { %>
|
||||||
|
<div class="field rss">
|
||||||
|
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16" width="16" height="16"><path fill-rule="evenodd" d="M8 5.5a2.5 2.5 0 100 5 2.5 2.5 0 000-5zM4 8a4 4 0 118 0 4 4 0 01-8 0z"></path></svg>
|
||||||
|
<div class="infos">
|
||||||
|
<div class="title"><%= title %></div>
|
||||||
|
<div class="date"><%= f.date(new Date(date), {dateStyle:"short"}) %></div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<% } %>
|
||||||
|
<% } else { %>
|
||||||
|
<div class="field">
|
||||||
|
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16" width="16" height="16"><path fill-rule="evenodd" d="M1.75 1.5a.25.25 0 00-.25.25v9.5c0 .138.112.25.25.25h2a.75.75 0 01.75.75v2.19l2.72-2.72a.75.75 0 01.53-.22h6.5a.25.25 0 00.25-.25v-9.5a.25.25 0 00-.25-.25H1.75zM0 1.75C0 .784.784 0 1.75 0h12.5C15.216 0 16 .784 16 1.75v9.5A1.75 1.75 0 0114.25 13H8.06l-2.573 2.573A1.457 1.457 0 013 14.543V13H1.75A1.75 1.75 0 010 11.25v-9.5zM9 9a1 1 0 11-2 0 1 1 0 012 0zm-.25-5.25a.75.75 0 00-1.5 0v2.5a.75.75 0 001.5 0v-2.5z"></path></svg>
|
||||||
|
Empty RSS feed
|
||||||
|
</div>
|
||||||
|
<% } %>
|
||||||
|
<% } %>
|
||||||
|
</section>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
<% } %>
|
||||||
@@ -904,6 +904,18 @@
|
|||||||
stroke-width: 6;
|
stroke-width: 6;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* RSS feed */
|
||||||
|
.rss {
|
||||||
|
align-items: flex-start;
|
||||||
|
}
|
||||||
|
.rss .infos {
|
||||||
|
margin-bottom: 3px;
|
||||||
|
}
|
||||||
|
.rss .infos .date {
|
||||||
|
font-size: 10px;
|
||||||
|
color: #666666;
|
||||||
|
}
|
||||||
|
|
||||||
/* Fade animation */
|
/* Fade animation */
|
||||||
.af {
|
.af {
|
||||||
opacity: 0;
|
opacity: 0;
|
||||||
|
|||||||
@@ -9,5 +9,6 @@
|
|||||||
"people",
|
"people",
|
||||||
"activity",
|
"activity",
|
||||||
"contributors",
|
"contributors",
|
||||||
"licenses"
|
"licenses",
|
||||||
|
"rss"
|
||||||
]
|
]
|
||||||
35
source/templates/repository/partials/rss.ejs
Normal file
35
source/templates/repository/partials/rss.ejs
Normal file
@@ -0,0 +1,35 @@
|
|||||||
|
<% if (plugins.rss) { %>
|
||||||
|
<section>
|
||||||
|
<h2 class="field">
|
||||||
|
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16" width="16" height="16"><path fill-rule="evenodd" d="M3.267 1.457c.3.286.312.76.026 1.06A6.475 6.475 0 001.5 7a6.472 6.472 0 001.793 4.483.75.75 0 01-1.086 1.034 8.89 8.89 0 01-.276-.304l.569-.49-.569.49A7.971 7.971 0 010 7c0-2.139.84-4.083 2.207-5.517a.75.75 0 011.06-.026zm9.466 0a.75.75 0 011.06.026A7.975 7.975 0 0116 7c0 2.139-.84 4.083-2.207 5.517a.75.75 0 11-1.086-1.034A6.475 6.475 0 0014.5 7a6.475 6.475 0 00-1.793-4.483.75.75 0 01.026-1.06zM8.75 8.582a1.75 1.75 0 10-1.5 0v5.668a.75.75 0 001.5 0V8.582zM5.331 4.736a.75.75 0 10-1.143-.972A4.983 4.983 0 003 7c0 1.227.443 2.352 1.177 3.222a.75.75 0 001.146-.967A3.483 3.483 0 014.5 7c0-.864.312-1.654.831-2.264zm6.492-.958a.75.75 0 00-1.146.967c.514.61.823 1.395.823 2.255 0 .86-.31 1.646-.823 2.255a.75.75 0 101.146.967A4.983 4.983 0 0013 7a4.983 4.983 0 00-1.177-3.222z"></path></svg>
|
||||||
|
<%= plugins.rss?.source ?? "" %> RSS feed
|
||||||
|
</h2>
|
||||||
|
<div class="row fill-width">
|
||||||
|
<section>
|
||||||
|
<% if (plugins.rss.error) { %>
|
||||||
|
<div class="field error">
|
||||||
|
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16" width="16" height="16"><path fill-rule="evenodd" d="M2.343 13.657A8 8 0 1113.657 2.343 8 8 0 012.343 13.657zM6.03 4.97a.75.75 0 00-1.06 1.06L6.94 8 4.97 9.97a.75.75 0 101.06 1.06L8 9.06l1.97 1.97a.75.75 0 101.06-1.06L9.06 8l1.97-1.97a.75.75 0 10-1.06-1.06L8 6.94 6.03 4.97z"></path></svg>
|
||||||
|
<%= plugins.rss.error.message %>
|
||||||
|
</div>
|
||||||
|
<% } else { %>
|
||||||
|
<% if (plugins.rss.feed.length) { %>
|
||||||
|
<% for (const {title, date} of plugins.rss.feed) { %>
|
||||||
|
<div class="field rss">
|
||||||
|
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16" width="16" height="16"><path fill-rule="evenodd" d="M8 5.5a2.5 2.5 0 100 5 2.5 2.5 0 000-5zM4 8a4 4 0 118 0 4 4 0 01-8 0z"></path></svg>
|
||||||
|
<div class="infos">
|
||||||
|
<div class="title"><%= title %></div>
|
||||||
|
<div class="date"><%= f.date(new Date(date), {dateStyle:"short"}) %></div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<% } %>
|
||||||
|
<% } else { %>
|
||||||
|
<div class="field">
|
||||||
|
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16" width="16" height="16"><path fill-rule="evenodd" d="M1.75 1.5a.25.25 0 00-.25.25v9.5c0 .138.112.25.25.25h2a.75.75 0 01.75.75v2.19l2.72-2.72a.75.75 0 01.53-.22h6.5a.25.25 0 00.25-.25v-9.5a.25.25 0 00-.25-.25H1.75zM0 1.75C0 .784.784 0 1.75 0h12.5C15.216 0 16 .784 16 1.75v9.5A1.75 1.75 0 0114.25 13H8.06l-2.573 2.573A1.457 1.457 0 013 14.543V13H1.75A1.75 1.75 0 010 11.25v-9.5zM9 9a1 1 0 11-2 0 1 1 0 012 0zm-.25-5.25a.75.75 0 00-1.5 0v2.5a.75.75 0 001.5 0v-2.5z"></path></svg>
|
||||||
|
Empty RSS feed
|
||||||
|
</div>
|
||||||
|
<% } %>
|
||||||
|
<% } %>
|
||||||
|
</section>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
<% } %>
|
||||||
Reference in New Issue
Block a user