Add Misskey support

Signed-off-by: Sam Therapy <sam@samtherapy.net>
This commit is contained in:
Sam Therapy 2022-02-06 14:46:27 -06:00
parent 73a0ccf871
commit 9ef773497b
Signed by: sam
GPG Key ID: 4D8B07C18F31ACBD
28 changed files with 1273 additions and 585 deletions

20
.drone.yml Normal file
View File

@ -0,0 +1,20 @@
kind: pipeline
type: docker
name: default
steps:
- name: dependencies
image: node
command: yarn
- name: lint
image: node
commands:
- yarn lint
depends: [dependencies]
- name: test
image: node
commands:
- yarn test
depends: [lint]

1
.eslintignore Normal file
View File

@ -0,0 +1 @@
src/public/infinite-scroll.js

29
.eslintrc.json Normal file
View File

@ -0,0 +1,29 @@
{
"env": {
"es2021": true,
"node": true
},
"extends": "eslint:recommended",
"parserOptions": {
"ecmaVersion": "latest",
"sourceType": "module"
},
"rules": {
"indent": [
"error",
4
],
"linebreak-style": [
"error",
"unix"
],
"quotes": [
"error",
"double"
],
"semi": [
"error",
"always"
]
}
}

132
.gitignore vendored
View File

@ -1,2 +1,130 @@
node_modules
*.atom
# Logs
logs
*.log
npm-debug.log*
yarn-debug.log*
yarn-error.log*
lerna-debug.log*
.pnpm-debug.log*
# Diagnostic reports (https://nodejs.org/api/report.html)
report.[0-9]*.[0-9]*.[0-9]*.[0-9]*.json
# Runtime data
pids
*.pid
*.seed
*.pid.lock
# Directory for instrumented libs generated by jscoverage/JSCover
lib-cov
# Coverage directory used by tools like istanbul
coverage
*.lcov
# nyc test coverage
.nyc_output
# Grunt intermediate storage (https://gruntjs.com/creating-plugins#storing-task-files)
.grunt
# Bower dependency directory (https://bower.io/)
bower_components
# node-waf configuration
.lock-wscript
# Compiled binary addons (https://nodejs.org/api/addons.html)
build/Release
# Dependency directories
node_modules/
jspm_packages/
# Snowpack dependency directory (https://snowpack.dev/)
web_modules/
# TypeScript cache
*.tsbuildinfo
# Optional npm cache directory
.npm
# Optional eslint cache
.eslintcache
# Optional stylelint cache
.stylelintcache
# Microbundle cache
.rpt2_cache/
.rts2_cache_cjs/
.rts2_cache_es/
.rts2_cache_umd/
# Optional REPL history
.node_repl_history
# Output of 'npm pack'
*.tgz
# Yarn Integrity file
.yarn-integrity
# dotenv environment variable files
.env
.env.development.local
.env.test.local
.env.production.local
.env.local
# parcel-bundler cache (https://parceljs.org/)
.cache
.parcel-cache
# Next.js build output
.next
out
# Nuxt.js build / generate output
.nuxt
dist
# Gatsby files
.cache/
# Comment in the public line in if your project uses Gatsby and not Next.js
# https://nextjs.org/blog/next-9-1#public-directory-support
# public
# vuepress build output
.vuepress/dist
# vuepress v2.x temp and cache directory
.temp
.cache
# Docusaurus cache and generated files
.docusaurus
# Serverless directories
.serverless/
# FuseBox cache
.fusebox/
# DynamoDB Local files
.dynamodb/
# TernJS port file
.tern-port
# Stores VSCode versions used for testing VSCode extensions
.vscode-test
# yarn v2
.yarn/cache
.yarn/unplugged
.yarn/build-state.yml
.yarn/install-state.gz
.pnp.*

View File

@ -1,8 +1,8 @@
# Mastofeed
# Fedifeed
Embed a mastodon feed in your blog et cetera.
Embed an activitypub feed in your blog et cetera.
https://www.mastofeed.com
https://www.fedifeed.com
## User guide
@ -14,24 +14,30 @@ The homepage has a tool for generating iframe code for you, with a sensible `san
#### GET `/api/v1/feed`
> example: `/api/feed?userurl=https%3A%2F%2Foctodon.social%2Fusers%2Ffenwick67&scale=90&theme=masto-light`
> example: `/api/v1/feed?userurl=https%3A%2F%2Foctodon.social%2Fusers%2Ffenwick67&scale=90&theme=masto-light`
Returns a html page which displays a mastodon feed for a user URL. Note that URLs must be URI encoded (i.e. `encodeURIComponent('https://octodon.social/users/fenwick67')` ).
Returns a html page which displays a feed for a user URL. Note that URLs must be URI encoded (i.e. `encodeURIComponent('https://octodon.social/users/fenwick67')` ).
Querystring options:
| option | required | description |
| ------ | -------- | ----------- |
| `userurl` | **yes** | Mastodon/ActivityPub account URL (usually `https://${instance}/users/${username}`) |
| `userurl` | **\*** | Mastodon/Pleroma/Misskey account URL (usually `https://${instance}/users/${username}` for MastoAPI or `https://${instance}/@${username}` for Misskey) |
| `instance` | **\*\***| Mastodon/Pleroma/Misskey instance URL (usually `https://${instance}`) |
| `user` | **\*\*** | Mastodon/Pleroma/Misskey user ID (usually `${username}`) |
| `feedurl` | no | a URL to a page of an ActivityPub post collection. Only used for pages beyond the first. |
| `theme` | no | either `masto-dark`, `masto-light` or `masto-auto`, to select the UI theme (default is `masto-dark`). `auto` will appear masto-light unless the user sets up masto-dark mode on their device. |
| `boosts` | no | whether to show boosts or not |
| `replies` | no | whether to show replies or not |
| `size` | no | the scale of the UI in percent. |
\* `userurl` is required if `instance` and `user` are not specified.\*\*\* \
\*\* `instance` **and** `user` are required if `userurl` is not specified.\*\*\*
\*\*\* **`userurl` and `instance`/`user` are mutually exclusive.**
## Server Installation
This is a straightforward node project with zero databases or anything, you should just be able to run `npm install` and then `npm start` to get up and running. Set your `PORT` environment variable to change the port it listens on.
This is a straightforward node project with zero databases or anything, you should just be able to run `yarn install` and then `yarn start` to get up and running. Set your `PORT` environment variable to change the port it listens on.
## Improve me

View File

@ -1,22 +0,0 @@
// build the styles
import { readFileSync, writeFileSync } from 'fs';
import { renderSync } from 'node-sass';
var staticDir = './static/'
var srcDir = './stylesrc/';
var themes = ['masto-light','masto-dark','masto-auto'];
themes.forEach(function(s){
var sassFile = srcDir+s+'.scss'
var cssFile = staticDir+s+'.css'
var result = renderSync({
data: readFileSync(sassFile,'utf8'),
includePaths:[srcDir]
});
writeFileSync(cssFile,result.css,'utf8')
});
console.log('ok');

117
index.js
View File

@ -1,117 +0,0 @@
import Express from 'express';
// v2 api
import convertv2 from './lib/convert.js';
import serveStatic from 'serve-static';
import cors from 'cors';
import errorPage from './lib/errorPage.js';
import morgan from 'morgan';
var app = Express();
var logger = morgan(':method :url :status via :referrer - :response-time ms')
app.use(
serveStatic('static',{
maxAge:'1d'
})
);
function doCache(res,durationSecs){
res.set({
"Cache-Control":"max-age="+durationSecs
})
}
// this just redirects to the
app.options('/api/feed',cors());
app.get('/api/feed',cors(),logger,function(req,res){
// get feed url
var feedUrl = req.query.url;
if (!feedUrl){
res.status(400);
res.send(errorPage(400,'You need to specify a feed URL'));
return;
}
var userUrl = feedUrl.replace(/\.atom.*/i,'');
var redirectUrl = '/api/v1/feed?';
var qs = ['userurl='+encodeURIComponent(userUrl),"api=v1"];
(['size','theme','boosts','replies']).forEach(key=>{
if (typeof req.query[key] != 'undefined'){
qs.push(key+'='+encodeURIComponent(req.query[key]));
}
})
res.redirect(redirectUrl + qs.join('&'));
});
app.options('/api/v1/feed',cors());
// http://localhost:8000/api/v1/feed?userurl=https%3A%2F%2Foctodon.social%2Fusers%2Ffenwick67
app.get('/api/v1/feed',cors(),logger,function(req,res){
// get feed url
var userUrl = req.query.userurl;
if (!userUrl){
res.status(400);
res.send(errorPage(400,'You need to specify a user URL'));
return;
}
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);
doCache(res,60*60);
res.send(data);
}).catch((er)=>{
res.status(500);
res.send(errorPage(500,null,{theme:opts.theme,size:opts.size}));
// TODO log the error
console.error(er,er.stack);
})
})
app.listen(process.env.PORT || 8000,function(){
console.log('Server started, listening on '+(process.env.PORT || 8000));
});

View File

@ -1,9 +1,9 @@
import { compile } from 'ejs';
import { readFileSync } from 'fs';
var template = compile(readFileSync('./lib/template.ejs', 'utf8'));
import { format } from 'timeago.js';
import { compile } from "ejs";
import { readFileSync } from "fs";
var template = compile(readFileSync("./lib/template.ejs", "utf8"));
import { format } from "timeago.js";
import got from 'got';
import got from "got";
const map = new Map();
const hour = 3600000;
@ -14,13 +14,13 @@ const hour = 3600000;
// a single process install it will be fine.
// note: rejects on HTTP 4xx or 5xx
async function apGet(url,ttl) {
async function apGet(url) {
return new Promise(function(resolve,reject){
// fail early
if (!url){
reject(new Error('URL is invalid'));
reject(new Error("URL is invalid"));
}
got( {
@ -30,11 +30,11 @@ async function apGet(url,ttl) {
"accept": "application/activity+json"
}
})
.then(response=>JSON.parse(response.body))
.then(resolve)
.catch(reject)
.then(response=>JSON.parse(response.body))
.then(resolve)
.catch(reject);
})
});
}
@ -42,31 +42,31 @@ async function apGet(url,ttl) {
async function promiseSome(proms){
function noRejectWrap(prom){
return new Promise(function(resolve,reject){
return new Promise(function(resolve){
prom // it's already been called
.then(resolve)
.catch(e=>{
.then(resolve)
.catch( ()=>{
// console.warn(e);// for debugging
resolve(null)
})
resolve(null);
});
})
});
}
return await Promise.all(proms.map(noRejectWrap))
return await Promise.all(proms.map(noRejectWrap));
}
export default async function (opts) {
var opts = opts;
// var opts = opts;
var feedUrl = opts.feedUrl;
var userUrl = opts.userUrl;
var isIndex = false;
if (!userUrl) {
throw new Error('need user URL');
throw new Error("need user URL");
}
var user, feed;
@ -83,7 +83,7 @@ export default async function (opts) {
var outbox = await apGet(user.outbox, 1 * hour);
// outbox.first can be a string for a URL, or an object with stuffs in it
if (typeof outbox.first == 'object'){
if (typeof outbox.first == "object"){
feed = outbox.first;
} else {
feed = await apGet(outbox.first, hour/6);// 10 mins. Because the base feed URL can get new toots quickly.
@ -110,7 +110,7 @@ function metaForUser(user) {
title: user.name||user.preferredUsername||null,
description: user.summary||null,
link:user.url||"#"
}
};
}
async function itemsForFeed(opts,user,feed) {
@ -125,7 +125,7 @@ async function itemsForFeed(opts,user,feed) {
boostData = await promiseSome(boostUrls.map(apGet));
// now get user data for each of those
let userData = await promiseSome(boostData.map(d=>d?d.attributedTo||'':null).map(apGet));
let userData = await promiseSome(boostData.map(d=>d?d.attributedTo||"":null).map(apGet));
// put a ._userdata key on the item object if this is a boost
for (var i = 0; i < boostData.length; i ++){
@ -155,18 +155,18 @@ async function itemsForFeed(opts,user,feed) {
}
if (index == -1){
console.warn("warning: couldn't match boost to item: ",boostToot)
console.warn("warning: couldn't match boost to item: ",boostToot);
return;
}
boostToot.object = boostToot;// this lets the later stage parser access object without errors :)
items[i] = boostToot;
})
});
}
return items.filter((item)=>{
return typeof item.object == 'object';// handle weird cases
return typeof item.object == "object";// handle weird cases
}).map((item)=>{
var enclosures = (item.object.attachment||[]).filter((a)=>{
@ -176,46 +176,46 @@ async function itemsForFeed(opts,user,feed) {
name:a.name,
type:a.mediaType,
url:a.url
}
};
});
var op = item._userdata?item._userdata:user;
return {
isBoost:!!item._userdata,
title:item._userdata?user.preferredUsername+' shared a status by '+op.preferredUsername:'',
title:item._userdata?user.preferredUsername+" shared a status by "+op.preferredUsername:"",
isReply:!!(item.object && item.object.inReplyTo),
hasCw:item.object.sensitive||false,
cw:item.object.summary,
content: item.object&&item.object.content?item.object.content:'',//TODO sanitize then render without entity escapes
atomHref:item.published?item.published.replace(/\W+/g,''):Math.random().toString().replace('.',''),// used for IDs
content: item.object&&item.object.content?item.object.content:"",//TODO sanitize then render without entity escapes
atomHref:item.published?item.published.replace(/\W+/g,""):Math.random().toString().replace(".",""),// used for IDs
enclosures:enclosures,
stringDate:item.published?getTimeDisplay(Date.parse(item.published)):'',
permalink:item.object.id?item.object.id:'#',
stringDate:item.published?getTimeDisplay(Date.parse(item.published)):"",
permalink:item.object.id?item.object.id:"#",
author:{
uri:op.url,// link to author page
avatar:op.icon&&op.icon.url?op.icon.url:'',
avatar:op.icon&&op.icon.url?op.icon.url:"",
displayName:op.name || op.preferredUsername,
fullName:op.preferredUsername+'@'+(new URL(op.url).hostname),
fullName:op.preferredUsername+"@"+(new URL(op.url).hostname),
}
}
})
};
});
}
function getNextPage(opts,user,feed){
//based on feed.next
if (!feed.next){return null}
if (!feed.next){return null;}
// take feed.next, uriencode it, then take user url, then take options.mastofeedUrl
var base = opts.mastofeedUrl.slice(0,opts.mastofeedUrl.indexOf('?'));
//var base = opts.mastofeedUrl.slice(0,opts.mastofeedUrl.indexOf("?"));
var ret = '/api/v1/feed?userurl=' + encodeURIComponent(opts.userUrl) + '&feedurl=' +encodeURIComponent(feed.next);
var ret = "/api/v1/feed?userurl=" + encodeURIComponent(opts.userUrl) + "&feedurl=" +encodeURIComponent(feed.next) + "&instance_type=" + opts.instance_type;
// add other params to the end
(['theme','header','size','boosts','replies']).forEach((k)=>{
if (typeof opts[k] != 'undefined'){
(["theme","header","size","boosts","replies"]).forEach((k)=>{
if (typeof opts[k] != "undefined"){
ret+=`&${k}=${ opts[k].toString() }`;
}
})
});
return ret;
}
@ -223,8 +223,8 @@ function getNextPage(opts,user,feed){
// utilities below
function getTimeDisplay(d) {
var d = d;
if (typeof d !== 'object') {
// var d = d;
if (typeof d !== "object") {
d = new Date(d);
}
// convert to number
@ -244,9 +244,9 @@ function getTimeDisplay(d) {
function isoDateToEnglish(d) {
var dt = d.split(/[t\-]/ig);
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];
return months[Number(dt[1]) - 1] + " " + dt[2] + ", " + dt[0];
}

View File

@ -1,16 +1,16 @@
import { compile } from 'ejs';
import { readFileSync } from 'fs';
var template = compile(readFileSync('./lib/template.ejs', 'utf8'));
import { compile } from "ejs";
import { readFileSync } from "fs";
var template = compile(readFileSync("./lib/template.ejs", "utf8"));
export default function(code,message,displayOptions){
var msg;
var displayOptions = displayOptions || {};
// const displayOptions = displayOptions || {};
if (code == 500 && !message){
msg = '<p>Sorry, we are having trouble fetching posts for this user. Please try again later.</p><br><p>If the issue persists, <a href="https://git.froth.zone/Sam/fedifeed/issues">please open an issue on Gitea</a>, or message sam@froth.zone</p>'
msg = "<p>Sorry, we are having trouble fetching posts for this user. Please try again later.</p><br><p>If the issue persists, <a href=\"https://git.froth.zone/Sam/fedifeed/issues\">please open an issue on Gitea</a>, or message sam@froth.zone</p>";
}else{
msg = message||'';
msg = message||"";
}
@ -23,14 +23,14 @@ export default function(code,message,displayOptions){
meta:{
title:code.toString(),
description:msg,
link:'#'
link:"#"
// avatar:'',
// headerImage:''
},
items:[],
nextPageLink:null,
isIndex:true
}
};
return template(options);
}

View File

@ -4,21 +4,30 @@
"ejs": "^3.1.6",
"express": "^4.17.2",
"feedparser": "^2.2.10",
"morgan": "^1.10.0",
"got": "^12.0.1",
"megalodon": "^4.0.0",
"morgan": "^1.10.0",
"request": "^2.88.2",
"request-promise-cache": "^2.0.1",
"serve-static": "^1.14.2",
"timeago.js": "^4.0.2"
"timeago.js": "^4.0.2",
"typescript": "^4.5.5"
},
"main": "index.js",
"type": "module",
"license": "MIT",
"scripts": {
"start": "node index.js",
"build-styles": "node build-styles.js"
"start": "yarn build-styles && node src/index.js",
"build-styles": "node src/build-styles.js",
"lint": "eslint --ext .js src lib",
"test": "echo \"Error: no test specified\" && exit 0"
},
"devDependencies": {
"@types/cors": "^2.8.12",
"@types/express": "^4.17.13",
"@types/morgan": "^1.9.3",
"@types/serve-static": "^1.13.10",
"eslint": "^8.8.0",
"node-sass": "^7.0.1"
}
}

22
src/build-styles.js Normal file
View File

@ -0,0 +1,22 @@
// build the styles
import { readFileSync, writeFileSync } from "fs";
import { renderSync } from "node-sass";
var staticDir = "./src/public/";
var srcDir = "./src/stylesrc/";
var themes = ["masto-light","masto-dark","masto-auto"];
themes.forEach(function(s){
var sassFile = srcDir+s+".scss";
var cssFile = staticDir+s+".css";
var result = renderSync({
data: readFileSync(sassFile,"utf8"),
includePaths:[srcDir]
});
writeFileSync(cssFile,result.css,"utf8");
});
console.log("ok");

130
src/index.js Normal file
View File

@ -0,0 +1,130 @@
import Express from "express";
// v2 api
import convertv2 from "../lib/convert.js";
import serveStatic from "serve-static";
import cors from "cors";
import errorPage from "../lib/errorPage.js";
import morgan from "morgan";
import { detector } from "megalodon";
const app = Express();
const logger = morgan(":method :url :status via :referrer - :response-time ms");
app.use(
serveStatic("src/public", {
maxAge: "1d",
}),
);
function doCache(res, durationSecs) {
res.set({
"Cache-Control": "max-age="+durationSecs,
});
}
// this just redirects to the
app.options("/api/feed", cors());
app.get("/api/feed", cors(), logger, function(req, res) {
// get feed url
const feedUrl = req.query.url;
if (!feedUrl) {
res.status(400);
res.send(errorPage(400, "You need to specify a feed URL"));
return;
}
const userUrl = feedUrl.replace(/\.atom.*/i, "");
const redirectUrl = "/api/v1/feed?";
const qs = ["userurl="+encodeURIComponent(userUrl), "api=v1"];
(["size", "theme", "boosts", "replies"]).forEach((key)=>{
if (typeof req.query[key] != "undefined") {
qs.push(key+"="+encodeURIComponent(req.query[key]));
}
});
res.redirect(redirectUrl + qs.join("&"));
});
app.options("/api/v1/feed", cors());
// http://localhost:8000/api/v1/feed?userurl=https%3A%2F%2Foctodon.social%2Fusers%2Ffenwick67
app.get("/api/v1/feed", cors(), logger, async function(req, res) {
// get feed url
// userUrl
let type = req.query.instance_type;
let userUrl = "";
if (type === "") {
const user = req.query.user;
const instance = req.query.instance;
let instanceType = await detector(instance);
if (instanceType === "mastodon" || instanceType === "pleroma") {
userUrl = instance + "/users/" + user;
type = instanceType;
} else if (instanceType === "misskey") {
userUrl = instance + "/@" + user;
type = instanceType;
} else {
res.status(400);
res.send(errorPage(400, "You need to specify a user URL"));
return;
}
} else {
userUrl = req.query.userurl;
}
const feedUrl = req.query.feedurl;
const 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.instance_type = type;
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);
doCache(res, 60 * 60);
res.send(data);
}).catch((er) => {
res.status(500);
res.send(errorPage(500, null, { theme: opts.theme, size: opts.size }));
// TODO log the error
console.error(er, er.stack);
});
});
app.listen(process.env.PORT || 8000, function() {
console.log("Server started, listening on "+(process.env.PORT || 8000));
});

View File

Before

Width:  |  Height:  |  Size: 1.5 KiB

After

Width:  |  Height:  |  Size: 1.5 KiB

View File

@ -3,7 +3,7 @@
<head>
<meta charset="utf-8">
<meta name="viewport" content="initial-scale=1">
<title>Mastofeed - embeddable Mastodon feeds</title>
<title>Fedifeed - embeddable ActivityPub feeds</title>
<link rel="stylesheet" href="./stylesheet.css">
</head>
@ -12,7 +12,7 @@
<div>
<h1>Mastofeed</h1>
<h4>Embedded Mastodon feeds for blogs etc.</h4>
<a href="https://github.com/fenwick67/mastofeed" class="cta button alt">Fork on Github <img
<a href="https://github.com/SamTherapy/fedifeed" class="cta button alt">Fork on Github <img
class="link-logo after" src="github-logo.svg" alt="Github Logo" data-reactid="19"></a><br>
<br>
<hr><br>
@ -61,7 +61,7 @@
<h3>Live Preview:</h3>
<span class="iframe-contain">
<iframe id="frame" allowfullscreen sandbox="allow-top-navigation allow-scripts" width="400" height="800"
src="/api/v1/feed?userurl=https%3A%2F%2Fmastodon.social%2Fusers%2Fgargron&replies=false&boosts=true"></iframe>
src=""></iframe>
</span>
<br>
</div>
@ -71,7 +71,9 @@
return document.getElementById(id).value;
}
var inUrl = 'https://' + val('urlin') + '/users/' + val('usernamein');
// var inUrl = 'https://' + val('urlin') + '/users/' + val('usernamein');
let user = val('usernamein');
let instance = "https://" + val('urlin');
var showBoosts = (!document.getElementById('hideboosts').checked).toString();
var showReplies = (!document.getElementById('hidereplies').checked).toString();
@ -79,7 +81,7 @@
var portStr = (window.location.port && window.location.port != 80) ? (':' + window.location.port) : ''
var iframeUrl = window.location.protocol + '//' + window.location.hostname + portStr
+ "/api/v1/feed?userurl=" + encodeURIComponent(inUrl) + "&theme=" + val('theme') + '&size=' + val('size')
+ "/api/v1/feed?user=" + encodeURIComponent(user) + "&instance=" + encodeURIComponent(instance) + "&instance_type=" + "&theme=" + val('theme') + '&size=' + val('size')
+ "&header=" + showHeader + '&replies=' + showReplies + '&boosts=' + showBoosts;
document.getElementById('result').value = '<iframe allowfullscreen sandbox="allow-top-navigation allow-scripts" width="' + val('width') + '" height="' + val('height') + '" src="' + iframeUrl + '"></iframe>';

File diff suppressed because one or more lines are too long

View File

@ -169,7 +169,7 @@ html,
body {
font-weight: normal; }
@media (prefers-color-scheme: dark) {
@media (prefers-color-scheme: masto-dark) {
html,
body {
background-color: #282c37;

File diff suppressed because one or more lines are too long

View File

@ -1,14 +1,14 @@
// do a test
import { createReadStream, writeFileSync } from 'fs';
import convert from '../lib/convert.js';
import { createReadStream, writeFileSync } from "fs";
import convert from "../lib/convert.js";
var r = createReadStream('./test/sample.atom');
var r = createReadStream("./test/sample.atom");
convert(r,function(er,data){
if (er){return console.log('error: ',er)}
console.log('ok');
writeFileSync('./test/result.html',data,'utf8');
})
if (er){return console.log("error: ",er);}
console.log("ok");
writeFileSync("./test/result.html",data,"utf8");
});

1188
yarn.lock

File diff suppressed because it is too large Load Diff