a feed appears (v2)
This commit is contained in:
parent
c8b93372c6
commit
c48fdfd7ec
4 changed files with 211 additions and 2 deletions
63
index.js
63
index.js
|
@ -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
123
lib/convertv2.js
Normal 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
26
npm-shrinkwrap.json
generated
|
@ -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",
|
||||
|
|
|
@ -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"
|
||||
},
|
||||
|
|
Reference in a new issue