mirror of
https://github.com/fenwick67/mastofeed
synced 2025-02-11 01:10:34 +01:00
a feed appears (v2)
This commit is contained in:
parent
c8b93372c6
commit
c48fdfd7ec
63
index.js
63
index.js
@ -1,5 +1,8 @@
|
|||||||
var Express = require('express');
|
var Express = require('express');
|
||||||
|
// v1 api
|
||||||
var convert = require('./lib/convert');
|
var convert = require('./lib/convert');
|
||||||
|
// v2 api
|
||||||
|
var convertv2 = require('./lib/convertv2');
|
||||||
var serveStatic = require('serve-static');
|
var serveStatic = require('serve-static');
|
||||||
var request = require('request');
|
var request = require('request');
|
||||||
var cors = require('cors');
|
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(){
|
app.listen(process.env.PORT || 8000,function(){
|
||||||
log('listening on '+(process.env.PORT || 8000));
|
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": {
|
"lodash": {
|
||||||
"version": "4.17.11",
|
"version": "4.17.11",
|
||||||
"resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.11.tgz",
|
"resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.11.tgz",
|
||||||
"integrity": "sha512-cQKh8igo5QUhZ7lg38DYWAxMvjSAKG0A8wGSVimP07SIUEK2UO+arSRKbRZWtelMtN5V0Hkwh5ryOto/SshYIg==",
|
"integrity": "sha512-cQKh8igo5QUhZ7lg38DYWAxMvjSAKG0A8wGSVimP07SIUEK2UO+arSRKbRZWtelMtN5V0Hkwh5ryOto/SshYIg=="
|
||||||
"dev": true
|
|
||||||
},
|
},
|
||||||
"lodash.assign": {
|
"lodash.assign": {
|
||||||
"version": "4.2.0",
|
"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": {
|
"require-directory": {
|
||||||
"version": "2.1.1",
|
"version": "2.1.1",
|
||||||
"resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz",
|
"resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz",
|
||||||
@ -1595,6 +1612,11 @@
|
|||||||
"readable-stream": "^2.0.1"
|
"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": {
|
"string-width": {
|
||||||
"version": "1.0.2",
|
"version": "1.0.2",
|
||||||
"resolved": "https://registry.npmjs.org/string-width/-/string-width-1.0.2.tgz",
|
"resolved": "https://registry.npmjs.org/string-width/-/string-width-1.0.2.tgz",
|
||||||
|
@ -5,6 +5,7 @@
|
|||||||
"express": "^4.16.4",
|
"express": "^4.16.4",
|
||||||
"feedparser": "^2.2.9",
|
"feedparser": "^2.2.9",
|
||||||
"request": "^2.88.0",
|
"request": "^2.88.0",
|
||||||
|
"request-promise-native": "^1.0.7",
|
||||||
"serve-static": "^1.13.2",
|
"serve-static": "^1.13.2",
|
||||||
"timeago.js": "^3.0.2"
|
"timeago.js": "^3.0.2"
|
||||||
},
|
},
|
||||||
|
Loading…
x
Reference in New Issue
Block a user