a feed appears (v2)

This commit is contained in:
fenwick67 2019-07-31 12:13:56 -04:00
parent c8b93372c6
commit c48fdfd7ec
4 changed files with 211 additions and 2 deletions

View File

@ -1,5 +1,8 @@
var Express = require('express');
// v1 api
var convert = require('./lib/convert');
// v2 api
var convertv2 = require('./lib/convertv2');
var serveStatic = require('serve-static');
var request = require('request');
var cors = require('cors');
@ -81,6 +84,66 @@ app.get('/api/feed',cors(),function(req,res){
});
app.options('/apiv2/feed',cors());
// http://localhost:8000/apiv2/feed?userurl=https%3A%2F%2Foctodon.social%2Fusers%2Ffenwick67
app.get('/apiv2/feed',cors(),function(req,res){
// get feed url
var userUrl = req.query.userurl;
if (!userUrl){
res.status(400);
res.send('You need to specify a user URL');
}
var feedUrl = req.query.feedUrl;
var opts = {};
if (req.query.size){
opts.size = req.query.size;
}
if (req.query.theme){
opts.theme = req.query.theme;
}
if (req.query.header){
if (req.query.header.toLowerCase() == 'no' || req.query.header.toLowerCase() == 'false'){
opts.header = false;
}else{
opts.header = true;
}
}
opts.boosts = true;
if (req.query.boosts){
if (req.query.boosts.toLowerCase() == 'no' || req.query.boosts.toLowerCase() == 'false'){
opts.boosts = false;
}else{
opts.boosts = true;
}
}
opts.replies = true;
if (req.query.replies){
if (req.query.replies.toLowerCase() == 'no' || req.query.replies.toLowerCase() == 'false'){
opts.replies = false;
}else{
opts.replies = true;
}
}
opts.userUrl = userUrl;
opts.feedUrl = feedUrl;
opts.mastofeedUrl = req.url;
convertv2(opts).then((data)=>{
res.status(200);
res.send(data);
}).catch((er)=>{
res.status(500);
res.send('Error fetching or parsing your feed.');
// TODO log the error
console.error(er);
})
})
app.listen(process.env.PORT || 8000,function(){
log('listening on '+(process.env.PORT || 8000));
});

123
lib/convertv2.js Normal file
View File

@ -0,0 +1,123 @@
var ejs = require('ejs');
var fs = require('fs');
var template = ejs.compile(fs.readFileSync('./lib/template.ejs', 'utf8'));
var timeAgo = require('timeago.js');
var request = require('request-promise-native')
// get JSON for an AP URL
async function apGet(url) {
return request.get( {
uri:url,
headers: {
"accept": "application/activity+json"
},
transform: function (body) {
return JSON.parse(body);
}
})
}
// accumulate a stream of XML into a html file
module.exports = async function (opts) {
var opts = opts;
var feedUrl = opts.feedUrl;
var userUrl = opts.userUrl;
var isIndex = false;
if (!userUrl) {
throw new Error('need user URL');
}
var user = await apGet(userUrl);
if (userUrl && !feedUrl) {
isIndex = true;
var outbox = await apGet(user.outbox);
feedUrl = outbox.first;
}
var feed = await apGet(feedUrl);
var items = itemsForFeed(feed);
var templateData = {
opts: opts,// from the request
meta: metaForUser(user),
items: itemsForFeed(feed),
nextPageLink: getNextPage(user,feed),
isIndex: isIndex
};
return template(templateData);
}
function metaForUser(user) {
return {
avatar: user.icon && user.icon.url?user.icon.url:null,
headerImage:user.image && user.image.url?user.image.url:null,
title: user.preferredUsername||null,
description: user.summary||null
}
}
// TODO make function
function itemsForFeed(feed) {
return feed.orderedItems.map((item)=>{
return {
isBoost:false,
title:'',
isReply:!!(item.object && item.object.inReplyTo),
hasCw:false,
cw:'',
atomHref:item.published?item.published.replace(/\W+/g,''):Math.random().toString().replace('.',''),
enclosures:[],//type, url
stringDate:item.published?getTimeDisplay(Date.parse(item.published)):'',
author:{
uri:'',// link to author page
avatar:'',// url of av
fullName:'',// display name
}
}
})
}
// TODO
function getNextPage(user,feed){
return null;
}
// utilities below
function getTimeDisplay(d) {
var d = d;
if (typeof d !== 'object') {
d = new Date(d);
}
// convert to number
dt = d.getTime();
var now = Date.now();
var delta = now - dt;
// over 6 days ago
if (delta > 1000 * 60 * 60 * 24 * 6) {
return isoDateToEnglish(d.toISOString());
} else {
return timeAgo().format(dt);
}
}
function isoDateToEnglish(d) {
var dt = d.split(/[t\-]/ig);
var months = ["January", "February", "March", "April", "May", "June",
"July", "August", "September", "October", "November", "December"];
return months[Number(dt[1]) - 1] + ' ' + dt[2] + ', ' + dt[0];
}

26
npm-shrinkwrap.json generated
View File

@ -861,8 +861,7 @@
"lodash": {
"version": "4.17.11",
"resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.11.tgz",
"integrity": "sha512-cQKh8igo5QUhZ7lg38DYWAxMvjSAKG0A8wGSVimP07SIUEK2UO+arSRKbRZWtelMtN5V0Hkwh5ryOto/SshYIg==",
"dev": true
"integrity": "sha512-cQKh8igo5QUhZ7lg38DYWAxMvjSAKG0A8wGSVimP07SIUEK2UO+arSRKbRZWtelMtN5V0Hkwh5ryOto/SshYIg=="
},
"lodash.assign": {
"version": "4.2.0",
@ -1403,6 +1402,24 @@
}
}
},
"request-promise-core": {
"version": "1.1.2",
"resolved": "https://registry.npmjs.org/request-promise-core/-/request-promise-core-1.1.2.tgz",
"integrity": "sha512-UHYyq1MO8GsefGEt7EprS8UrXsm1TxEvFUX1IMTuSLU2Rh7fTIdFtl8xD7JiEYiWU2dl+NYAjCTksTehQUxPag==",
"requires": {
"lodash": "^4.17.11"
}
},
"request-promise-native": {
"version": "1.0.7",
"resolved": "https://registry.npmjs.org/request-promise-native/-/request-promise-native-1.0.7.tgz",
"integrity": "sha512-rIMnbBdgNViL37nZ1b3L/VfPOpSi0TqVDQPAvO6U14lMzOLrt5nilxCQqtDKhZeDiW0/hkCXGoQjhgJd/tCh6w==",
"requires": {
"request-promise-core": "1.1.2",
"stealthy-require": "^1.1.1",
"tough-cookie": "^2.3.3"
}
},
"require-directory": {
"version": "2.1.1",
"resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz",
@ -1595,6 +1612,11 @@
"readable-stream": "^2.0.1"
}
},
"stealthy-require": {
"version": "1.1.1",
"resolved": "https://registry.npmjs.org/stealthy-require/-/stealthy-require-1.1.1.tgz",
"integrity": "sha1-NbCYdbT/SfJqd35QmzCQoyJr8ks="
},
"string-width": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/string-width/-/string-width-1.0.2.tgz",

View File

@ -5,6 +5,7 @@
"express": "^4.16.4",
"feedparser": "^2.2.9",
"request": "^2.88.0",
"request-promise-native": "^1.0.7",
"serve-static": "^1.13.2",
"timeago.js": "^3.0.2"
},