diff --git a/index.js b/index.js index cedeecc..20adb3f 100644 --- a/index.js +++ b/index.js @@ -40,8 +40,6 @@ The MIT License: THE SOFTWARE. */ var Express = require('express'); -// v1 api -var convert = require('./lib/convert'); // v2 api var convertv2 = require('./lib/convertv2'); var serveStatic = require('serve-static'); diff --git a/lib/convert.js b/lib/convert.js deleted file mode 100644 index e02bc90..0000000 --- a/lib/convert.js +++ /dev/null @@ -1,353 +0,0 @@ -/* -AGPL + MIT License - - Copyright (C) 2022 Nicco Kunzmann - - This program is free software: you can redistribute it and/or modify - it under the terms of the GNU Affero General Public License as published - by the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU Affero General Public License for more details. - - You should have received a copy of the GNU Affero General Public License - along with this program. If not, see . - - -The MIT License: - - Copyright © 2017 fenwick67 - - Permission is hereby granted, free of charge, to any person obtaining a copy - of this software and associated documentation files (the "Software"), to deal - in the Software without restriction, including without limitation the rights - to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - copies of the Software, and to permit persons to whom the Software is - furnished to do so, subject to the following conditions: - - The above copyright notice and this permission notice shall be included in - all copies or substantial portions of the Software. - - THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - THE SOFTWARE. -*/ -var FeedParser = require('feedparser'); -var ejs = require('ejs'); -var fs = require('fs'); -var template = ejs.compile(fs.readFileSync('./lib/template.ejs','utf8')); -var timeAgo = require('timeago.js'); - -function isArray(a){ - return Array.isArray(a); -} - -// accumulate a stream of XML into a html file - -module.exports = function(stream,opts,callback){ - var callback = callback; - var opts = opts; - if (typeof opts == 'function'){ - callback = opts; - opts = {}; - } - - // convert s from atom feed to a full html page for rendering - breakDown(stream,function(er,data){ - if (er) { - return callback(er); - } - // try and build up - try{ - var result = buildUp(data,opts) - }catch(e){ - return callback(e); - } - return callback(null,result); - }); - -} - -// break the xml into json -function breakDown(stream,callback){ - - var spent = false; - function cbOnce(er,data){ - if (!spent){ - callback(er,data); - spent = true; - } - } - - stream.on('error',cbOnce); - var feedparser = new FeedParser(); - feedparser.on('error', cbOnce); - stream.pipe(feedparser) - - - feedparser.items = []; - feedparser.on('readable', function () { - // This is where the action is! - var stream = this; // `this` is `feedparser`, which is a stream - var items = []; - var item; - - while (item = stream.read()) { - feedparser.items.push(item); - } - - - }); - - feedparser.on('end',function(er){cbOnce(null,feedparser)}); - -} - -// hydrate the json to html -function buildUp(jsonObj,opts){ - - // assign opts to the obj - jsonObj.opts = opts||{}; - - // iterate through the items - jsonObj.items = jsonObj.items.filter(function(item){ - - // get date - item.stringDate = getTimeDisplay(item.date); - - item.content = getH(item,'atom:content'); - if (!item.content ){// item was deleted - return false; - } - - // make anchor tags have the "_top" target - item.content = item.content.replace(/\<\s*a\s*/ig,'http://activitystrea.ms/schema/1.0/share - item.isReply = false; - - var v = getH(item,'activity:verb') - if (v.indexOf('share') > -1){ - item.isBoost = true; - } - - if (item['thr:in-reply-to']){ - item.isReply = true; - } - - if(item.summary){ - item.hasCw = true; - item.cw = item.summary; - } - - if(item['activity:object'] && item['activity:object'].summary && item['activity:object'].summary['#']){ - item.hasCw = true; - item.cw = item['activity:object'].summary['#']; - } - - - // get a pagination ID for an entry - item.paginationId = false; - if (item['atom:link']){ - var links = item['atom:link']; - if (!isArray(links) && typeof links == 'object'){ - links = [links]; - }else if (!isArray(links)){ - links = []; - } - links.forEach((link)=>{ - if (!link['@']){return} - if (link['@']['rel']=='self'){ - // parse out the pagination id - // href looks like this in mastodon: https://octodon.social/users/fenwick67/updates/732275.atom - // href looks like this in pleroma (and we should ignore): https://social.fenwick.pizza/objects/1e2fa906-378c-43f8-98fa-271aae455758 - var href = link['@']['href']; - if (!href){return} - item.atomHref = href; - var match = href.match(/\/\d+.atom/); - if(!match){return} - var id = match[0].replace(/\D/g,''); - if (id){ - item.paginationId = id; - }else{ - return; - } - } - }) - - } - - return true; - - }); - - if (jsonObj.meta && jsonObj.meta['atom:author'] && jsonObj.meta['atom:author'].link && Array.isArray(jsonObj.meta['atom:author'].link) ){ - jsonObj.meta['atom:author'].link.forEach(link=>{ - var l = link['@']; - if (l.rel=="header"){ - jsonObj.meta.headerImage = l.href; - } - else if(l.rel=="avatar"){ - jsonObj.meta.avatar = l.href; - } - }); - } - - - // get next page - jsonObj.feedUrl = opts.feedUrl; - jsonObj.isIndex = (opts.feedUrl.indexOf('?') == -1); - - // prefer link(rel=next) - var nextPageFeedUrl = ''; - var links = jsonObj.meta['atom:link']; - if (links){ - if (!isArray(links) && typeof links == 'object'){ - links = [links]; - }else if (!isArray(links)){ - links = []; - } - links.forEach(function(link){ - if (link['@'] && link['@']['rel'] == 'next' && link['@']['href']){ - nextPageFeedUrl = link['@']['href']; - } - }) - } - - if (!nextPageFeedUrl){ - // alternative: try to get the oldest entry id on this page - var lowestId = Infinity; - jsonObj.items.forEach(function(item){ - var id = Number(item.paginationId); - if ( id < lowestId ){ - lowestId = id; - } - }); - - if (lowestId < Infinity && opts.feedUrl){ - nextPageFeedUrl = opts.feedUrl.replace(/\?.+/g,'') + '?max_id='+lowestId; - } - } - - if(nextPageFeedUrl){ - jsonObj.nextPageLink = opts.mastofeedUrl.replace(encodeURIComponent(opts.feedUrl),encodeURIComponent(nextPageFeedUrl)); - console.log(jsonObj.nextPageLink); - } - return template(jsonObj); -} - -// utilities below - - -// get obj[key]['#'] or '' -function getH(obj,key){ - if (!obj[key]){return ''} - return obj[key]['#']||''; -} - -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]; -}