Comparing version 0.3.0 to 0.4.0
@@ -0,1 +1,11 @@ | ||
# v0.4.0 | ||
Adds: | ||
- Improved Web Design | ||
- Auto-update RSS feeds | ||
- Custom port and host values for `cream serve` | ||
- Add RSS sorting by date, independent of feed | ||
- Add `%pubdate%` option for format options | ||
- Add `%update%` option for website templates which get's replaced with an auto-update script | ||
# v0.3.0 | ||
@@ -2,0 +12,0 @@ |
@@ -5,3 +5,3 @@ ![header](./assets/Favicon.png) | ||
# Creamcrop <small>v0.3.0</small> | ||
# Creamcrop <small>v0.4.0</small> | ||
@@ -8,0 +8,0 @@ > A cream-of-the-crop, top-of-the-top, slice-and-chop, absolutely minimalist news getter |
> Configuration for the package | ||
Configuration for the package is located at the `.creamcroprc` file, | ||
which is auto-generated, and currently only contains the feeds to use | ||
when generating the webiste. However, there are plans to extend this | ||
to allow for more configuration in the package, including custom formats, | ||
website templates, and more. | ||
which is auto-generated, and contains easy ways to add custom HTML templates | ||
and format's for the website when served. | ||
## Configuration Syntax | ||
@@ -32,3 +29,3 @@ | ||
| `feeds` | Array of feeds to parse | No default. **Required**. | An array of URLs to feeds | | ||
| `format` | The format of the output. Each value should be surrounded by `%`. | `<a href="%link%">%item%</a> from <a href="%feedlink%">%feed%</a>` | `%feed%`- The name of the RSS feed the item is in. <br> `%feedlink%` - The RSS feed's link that the item is in. <br> `%item%` - The name of the RSS feed Item. <br> `%itemlink%` Link to the item. | | ||
| `custom` | A custom HTML template. Inside the HTML, use `%feed%`, which will be replaced by the content of the feed. | A basic HTML page. | The relative path to the HTML template file | | ||
| `format` | The format of the output. Each value should be surrounded by `%`. | `<a href="%link%">%title%</a> from <a href="%feedlink%">%feed%</a>` | `%feed%`- The name of the RSS feed the item is in. <br> `%feedlink%` - The RSS feed's link that the item is in. <br> `%title%` - The name of the RSS feed Item. <br> `%link%` Link to the item. <br> `%pubdate%` - The publication date. | | ||
| `custom` | A custom HTML template. Inside the HTML, use `%feed%`, which will be replaced by the content of the feed. Use `%update%` in the HTML, which will be replaced by a script that auto-updates the RSS feed. | A basic HTML page. | The relative path to the HTML template file | |
@@ -79,3 +79,3 @@ > Learn the fundamentals of creamcrop | ||
Qlabs (@Quantalabs) | ||
0.3.0 | ||
0.4.0 | ||
``` | ||
@@ -121,3 +121,3 @@ | ||
$ cream --version | ||
0.3.0 | ||
0.4.0 | ||
``` |
{ | ||
"name": "creamcrop", | ||
"version": "0.3.0", | ||
"version": "0.4.0", | ||
"description": "A cream-of-the-crop, top-of-the-top, slice-and-chop, absolutely minimalist news getter.", | ||
@@ -5,0 +5,0 @@ "main": "src/index.js", |
@@ -23,3 +23,3 @@ <div align='center'> | ||
(creamcrop|cream) fetch [url] Fetch a feed. | ||
(creamcrop|cream) serve [url] Serves website from RSS feed | ||
(creamcrop|cream) serve [dir] Serves website from config file in [dir]. | ||
(creamcrop|cream) about Displays package info and exits. | ||
@@ -26,0 +26,0 @@ |
@@ -76,2 +76,20 @@ #!/usr/bin/env node | ||
description: 'The directory of the config file.' | ||
}), | ||
yargs.option('port', { | ||
alias: 'p', | ||
type: 'number', | ||
default: 8080, | ||
description: 'The port to run the server on.' | ||
}), | ||
yargs.option('host', { | ||
alias: 'h', | ||
type: 'string', | ||
default: 'localhost', | ||
description: 'The host to run the server on.' | ||
}), | ||
yargs.option('interval', { | ||
alias: 'i', | ||
type: 'number', | ||
default: 300000, | ||
description: 'The interval to check for new posts. Defaults to 5 minutes.' | ||
}) | ||
@@ -81,3 +99,3 @@ }, | ||
(async () => { | ||
await web.serve(argv.dir) | ||
await web.serve(argv.dir, argv.port, argv.host, argv.interval) | ||
})(); | ||
@@ -126,4 +144,8 @@ } | ||
process.on('SIGINT', function() { | ||
console.log('\nExiting...') | ||
process.exit(0) | ||
}); | ||
exports.about = about | ||
exports.version = version |
const http = require('http'); | ||
const fs = require('fs'); | ||
const rss = require('./rss'); | ||
const metadata = require('./metadata'); | ||
@@ -10,3 +11,3 @@ /** | ||
*/ | ||
async function serve(dir) { | ||
async function serve(dir, port, host, interval) { | ||
if (fs.existsSync(dir+'/.creamcroprc') || fs.existsSync(dir+'.creamcroprc')) { | ||
@@ -19,84 +20,123 @@ console.log('Found config file, generating website...') | ||
} | ||
let feed = { | ||
items: [] | ||
}; | ||
let config = JSON.parse(fs.readFileSync(dir+'/.creamcroprc')); | ||
for (var x in config.feeds) { | ||
let data = await rss.parse(config.feeds[x]); | ||
for (var fitem in data.items) { | ||
feed.items.push({ | ||
title: data.items[fitem].title, | ||
link: data.items[fitem].link, | ||
feed: data.title, | ||
feedlink: data.link, | ||
}); | ||
async function generate(dir) { | ||
let feed = { | ||
items: [] | ||
}; | ||
let config = JSON.parse(fs.readFileSync(dir+'/.creamcroprc')); | ||
for (var x in config.feeds) { | ||
let data = await rss.parse(config.feeds[x]); | ||
for (var fitem in data.items) { | ||
feed.items.push({ | ||
title: data.items[fitem].title, | ||
link: data.items[fitem].link, | ||
feed: data.title, | ||
feedlink: data.link, | ||
pubdate: data.items[fitem].isoDate | ||
}); | ||
} | ||
} | ||
} | ||
function format(title, link, feedlink, feed) { | ||
if (config.format !== undefined) { | ||
var format = config.format | ||
format = format.replace(/%title%/g, title); | ||
format = format.replace(/%link%/g, link); | ||
format = format.replace(/%feed%/g, feed); | ||
format = format.replace(/%feedlink%/g, feedlink); | ||
return format; | ||
// Sort all the items in feed.items by date | ||
feed.items = feed.items.sort(function(a, b) { | ||
return new Date(b.pubdate) - new Date(a.pubdate); | ||
}); | ||
function format(title, link, feedlink, feed, pubdate, add="", end="") { | ||
if (config.format !== undefined) { | ||
var format = config.format | ||
format = format.replace(/%title%/g, title); | ||
format = format.replace(/%link%/g, link); | ||
format = format.replace(/%feed%/g, feed); | ||
format = format.replace(/%feedlink%/g, feedlink); | ||
format = format.replace(/%pubdate%/g, new Date(pubdate).toLocaleDateString()); | ||
return format; | ||
} | ||
else { | ||
return `${add}<a href="${link}">${title}</a> from <a href="${feedlink}">${feed}</a>${end}`; | ||
} | ||
} | ||
else { | ||
return `<a href="${link}">${title}</a> from <a href="${feedlink}">${feed}</a>`; | ||
} | ||
} | ||
let html = '' | ||
let html = '' | ||
if (config.custom !== undefined) { | ||
console.log('\nParsing custom HTML...'); | ||
if (config.custom !== undefined) { | ||
console.log('\nParsing custom HTML...'); | ||
let customconf = '' | ||
if (fs.existsSync(dir+config.custom)) { | ||
customconf = fs.readFileSync(dir+config.custom, {encoding:'utf8', flag:'r'}); | ||
} | ||
else if (fs.existsSync(dir+'/'+config.custom)) { | ||
customconf = fs.readFileSync(dir+'/'+config.custom, {encoding:'utf8', flag:'r'}); | ||
} | ||
else { | ||
console.log('Custom file not found: ' + dir+config.custom); | ||
process.exit(1); | ||
} | ||
let customconf = '' | ||
if (fs.existsSync(dir+config.custom)) { | ||
customconf = fs.readFileSync(dir+config.custom, {encoding:'utf8', flag:'r'}); | ||
} | ||
else if (fs.existsSync(dir+'/'+config.custom)) { | ||
customconf = fs.readFileSync(dir+'/'+config.custom, {encoding:'utf8', flag:'r'}); | ||
} | ||
else { | ||
console.log('Custom file not found: ' + dir+config.custom); | ||
process.exit(1); | ||
} | ||
console.log('\nParsing RSS feed(s)...'); | ||
customconf = customconf.replace(/%feed%/g, feed.items.map(item => ` | ||
<li> | ||
${format(item.title, item.link, item.feedlink, item.feed)} | ||
</li> | ||
`).join('\n')); | ||
console.log('\nParsing RSS feed(s)...'); | ||
customconf = customconf.replace(/%feed%/g, feed.items.map(item => ` | ||
${format(item.title, item.link, item.feedlink, item.feed, item.pubdate)} | ||
`).join('\n')); | ||
// Replace %update% with automatic reloading script with interval in customconf | ||
customconf = customconf.replace(/%update%/g, ` | ||
<script> | ||
setTimeout(function(){ | ||
window.location.reload(1); | ||
}, ${Number(interval)}); | ||
</script> | ||
`); | ||
html = customconf | ||
} | ||
html = customconf | ||
} | ||
else { | ||
console.log('\nParsing RSS feed(s)...\n'); | ||
html = ` | ||
<!DOCTYPE html> | ||
<html> | ||
<head> | ||
<title>Creamcrop | A cream-of-the-crop, top-of-the-top, slice-and-chop, absolutely minimalist news getter</title> | ||
</head> | ||
<body> | ||
<h1>Your News Feed</h1> | ||
<sub>Your news feed from creamcrop, the cream-of-the-crop, top-of-the-top, slice-and-chop, absolutely minimalist news getter.</sub> | ||
<ul> | ||
${feed.items.map(item => ` | ||
<li> | ||
${format(item.title, item.link, item.feedlink, item.feed)} | ||
</li> | ||
`).join('\n')} | ||
</ul> | ||
</body> | ||
</html> | ||
`; | ||
else { | ||
console.log('\nParsing RSS feed(s)...\n'); | ||
html = ` | ||
<!DOCTYPE html> | ||
<html> | ||
<head> | ||
<title>Creamcrop | A cream-of-the-crop, top-of-the-top, slice-and-chop, absolutely minimalist news getter</title> | ||
<link rel="preconnect" href="https://fonts.googleapis.com"> | ||
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin> | ||
<link href="https://fonts.googleapis.com/css2?family=Georama&display=swap" rel="stylesheet"> | ||
<meta charset="utf-8"> | ||
<meta name="generator" content="Creamcrop ${metadata.version}" /> | ||
</head> | ||
<body style="font-family: 'Georama', sans-serif; margin: 0; border: none; padding: 0; overflow-x: hidden;"> | ||
<section id="main-content"> | ||
<h1 style="width: 100vw; text-align: center;">Your News Feed</h1> | ||
<p style="margin: auto; text-align: center;">Your news feed from creamcrop, the cream-of-the-crop, top-of-the-top, slice-and-chop, absolutely minimalist news getter.</p> | ||
<br> | ||
<hr style="width: 50vw; margin: auto;"> | ||
<br> | ||
<ol style="width: 100vw; text-align: center; list-style-position: inside;"> | ||
${feed.items.map(item => ` | ||
${format(item.title, item.link, item.feedlink, item.feed, item.pubdate, '<li>', '</li>')} | ||
`).join('\n')} | ||
</ol style="width: 100vw; text-align: center;"> | ||
</section> | ||
<br><br> | ||
<!-- Add footer --> | ||
<footer style="width: 100vw; text-align: center; bottom: 0; position: fixed; background-color: white;"> | ||
<p>Creamcrop | A cream-of-the-crop, top-of-the-top, slice-and-chop, absolutely minimalist news getter</p> | ||
</footer> | ||
<script> | ||
setTimeout(function(){ | ||
window.location.reload(1); | ||
}, ${Number(interval)}); | ||
</script> | ||
</body> | ||
</html> | ||
`; | ||
} | ||
return html; | ||
} | ||
const requestListener = function (req, res) { | ||
let html = await generate(dir); | ||
const requestListener = async function (req, res) { | ||
res.writeHead(200, { | ||
@@ -106,9 +146,15 @@ 'Content-Type': 'text/html' | ||
res.end(html); | ||
if (req.url === '/') { | ||
html = await generate(dir); | ||
res.end(html); | ||
} | ||
} | ||
const server = http.createServer(requestListener); | ||
server.listen(8080); | ||
console.log('\n\nServer running at http://localhost:8080') | ||
const server = await http.createServer(requestListener); | ||
server.listen(port, host, () => { | ||
console.log(`Server is running on http://${host}:${port}`); | ||
}); | ||
} | ||
exports.serve = serve |
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
147698
38
300