From f00ba92ed2cc1a9c24ad783e83525d1b5a85b857 Mon Sep 17 00:00:00 2001 From: tomsmeding Date: Tue, 13 Sep 2016 11:43:06 +0200 Subject: Initial --- modules/$common.js | 33 +++ modules/abbrgen/abbreviation_gen_Darwin | Bin 0 -> 30896 bytes modules/abbrgen/abbreviation_gen_Linux | Bin 0 -> 19364 bytes modules/abbrgen/abbrgen.js | 49 +++++ modules/changes/changes.html | 257 ++++++++++++++++++++++++ modules/changes/changes.js | 163 +++++++++++++++ modules/datumpjeprik/datumpjeprik.html | 168 ++++++++++++++++ modules/datumpjeprik/datumpjeprik.js | 66 ++++++ modules/ip/ip.js | 8 + modules/nlen/English-Dutch-mistranslations.json | 31 +++ modules/nlen/nlen.html | 11 + modules/nlen/nlen.js | 17 ++ modules/poke/poke.html | 125 ++++++++++++ modules/poke/poke.js | 47 +++++ modules/quotesgrab/quotesgrab.js | 65 ++++++ modules/subd-krokodil/subd-krokodil.js | 21 ++ modules/ytdl/youtube-dl-Darwin | Bin 0 -> 1149466 bytes modules/ytdl/ytdl.html | 45 +++++ modules/ytdl/ytdl.js | 31 +++ 19 files changed, 1137 insertions(+) create mode 100644 modules/$common.js create mode 100755 modules/abbrgen/abbreviation_gen_Darwin create mode 100755 modules/abbrgen/abbreviation_gen_Linux create mode 100644 modules/abbrgen/abbrgen.js create mode 100644 modules/changes/changes.html create mode 100644 modules/changes/changes.js create mode 100644 modules/datumpjeprik/datumpjeprik.html create mode 100644 modules/datumpjeprik/datumpjeprik.js create mode 100644 modules/ip/ip.js create mode 100644 modules/nlen/English-Dutch-mistranslations.json create mode 100644 modules/nlen/nlen.html create mode 100644 modules/nlen/nlen.js create mode 100644 modules/poke/poke.html create mode 100644 modules/poke/poke.js create mode 100644 modules/quotesgrab/quotesgrab.js create mode 100644 modules/subd-krokodil/subd-krokodil.js create mode 100755 modules/ytdl/youtube-dl-Darwin create mode 100644 modules/ytdl/ytdl.html create mode 100644 modules/ytdl/ytdl.js (limited to 'modules') diff --git a/modules/$common.js b/modules/$common.js new file mode 100644 index 0000000..fa29c50 --- /dev/null +++ b/modules/$common.js @@ -0,0 +1,33 @@ +var path=require("path"), + basicAuth=require("basic-auth"); + +var cwd=process.cwd(); +var globalAccounts=require(cwd+"/globalAccounts.json"); + +module.exports={ + "rootdir":path.dirname(cwd), + "serverdir":cwd, + "simpleHTMLescape":function simpleHTMLescape(str){ + return str.replace(/&/g,'&').replace(//g,'>'); + }, + "authgen":function authgen(accounts){ //omit `accounts` to use the globalAccounts list + if(!accounts)accounts=globalAccounts; + return function (req,res,next){ + function unauth(res){ + res.set("WWW-Authenticate","Basic realm=Authorization required"); + return res.sendStatus(401); + }; + var user=basicAuth(req); + if(!user||!user.name||!user.pass){ + return unauth(res); + } + var i; + for(i=0;i5000){ + res.send("ERROR: Number of abbreviations too large."); + return; + } + if(!abbr.match(/^[a-z]+$/i)||isNaN(+num)){ + res.send("ERROR: Invalid input values."); + return; + } + get_abbreviations(abbr,num,function(answers){ + res.send(answers.join("\n")); + }); + }); +}; diff --git a/modules/changes/changes.html b/modules/changes/changes.html new file mode 100644 index 0000000..cda3da1 --- /dev/null +++ b/modules/changes/changes.html @@ -0,0 +1,257 @@ + + + + +Website change monitor + + + + +

Website change monitor

+URLs: + +
+
+
+
+
+
+ + +
+
+
+

+ + + +
DateHash
+
+ + diff --git a/modules/changes/changes.js b/modules/changes/changes.js new file mode 100644 index 0000000..6a8c8f2 --- /dev/null +++ b/modules/changes/changes.js @@ -0,0 +1,163 @@ +"use strict"; + +var cmn=require("../$common.js"), + persist=require("node-persist"), + crypto=require("crypto"), + http=require("http"), + https=require("https"), + URL=require("url"); + +var moddir=null; + +persist=persist.create({ + dir:"persist/changes", + continuous:false, + interval:false +}); +persist.initSync(); + +//urls: map(url => URLobject) +//url: String +//URLobject: {url, timeline: [[Date, hash]]} +var urls=persist.getItemSync("urls"); +if(!urls){ + urls={}; + persist.setItemSync("urls",urls); +} + + +function URLobject(url){ + if(!(this instanceof URLobject))return new URLobject(url); + this.url=url; + this.timeline=[]; +} + +function fetch(method,url,data/*?*/,cb){ + var cbcalled=false; + + if(!cb){ + cb=data; + data=undefined; + if(!cb)throw new Error("No callback passed to fetch"); + } + + try { + url=URL.parse(url); + } catch(e){ + cb(-1,null); + return; + } + + var httpclass; + switch(url.protocol){ + case "http:": httpclass=http; break; + case "https:": httpclass=https; break; + default: + cb(-1,null); + return; + } + + url.method=method; + + var req=httpclass.request(url,function(res){ + var body=""; + res.on("data",function(data){ + body+=data; + }); + res.on("end",function(){ + if(!cbcalled)cb(res.statusCode,body); + cbcalled=true; + }); + res.on("error",function(err){ + if(!cbcalled)cb(-1,err); + cbcalled=true; + }); + }); + req.on("error",function(err){ + if(!cbcalled)cb(-1,err); + cbcalled=true; + }); + if(data)req.write(data); + req.end(); +} + +function refreshURLs(){ + var hashes={}; + var i; + var url; + var timeout=null; + for(url in urls){ + console.log("Fetching <"+url+">"); + fetch("GET",url,function(url,status,body){ + console.log("Got <"+url+">; status = "+status); + if(status==-1){ + hashes[url]=[new Date(),null]; + } else { + var hash=crypto.createHash("sha256"); + hash.update(body); + hashes[url]=[new Date(),hash.digest("hex")]; + } + + if(!urls[url]){ + console.log("WARNING: url <"+url+"> from hashes not found in urls!"); + return; + } + //var last=urls[url].timeline[urls[url].timeline.length-1]; + //if(last==undefined||hashes[url][1]==null||hashes[url][1]!=last[1]){ + urls[url].timeline.push(hashes[url]); + //} + + if(timeout)clearTimeout(timeout); + timeout=setTimeout(function(){ + persist.setItemSync("urls",urls); + console.log("(persisted after refresh)") + },2000); + }.bind(null,url)); + } +} + + +module.exports=function(app,io,_moddir){ + moddir=_moddir; + app.all(["/changes","/changes/*"],cmn.authgen()); + app.get("/changes",function(req,res){ + res.sendFile(moddir+"/changes.html"); + }); + app.get("/changes/urls",function(req,res){ + var list=[]; + var url; + for(url in urls)list.push(url); + res.send(JSON.stringify(list)); + }); + app.get("/changes/url",function(req,res){ + var url=req.query.url; + if(!urls[url]){ + res.status(404); + res.send("URL not found in watch list"); + return; + } + res.send(JSON.stringify(urls[url])); + }); + app.post("/changes/url",function(req,res){ + var url=req.body; + urls[url]=new URLobject(url); + persist.setItemSync("urls",urls); + // refreshURLs(); + res.send(); + }); + app.delete("/changes/url",function(req,res){ + var url=req.body; + if(!urls[url]){ + res.status(404); + res.send("URL not found in watch list"); + return; + } + delete urls[url]; + persist.setItemSync("urls",urls); + res.send(); + }); + app.post("/changes/refresh",function(req,res){ + refreshURLs(); + res.send(); + }); +}; diff --git a/modules/datumpjeprik/datumpjeprik.html b/modules/datumpjeprik/datumpjeprik.html new file mode 100644 index 0000000..46a21d3 --- /dev/null +++ b/modules/datumpjeprik/datumpjeprik.html @@ -0,0 +1,168 @@ + + + + +Datumpje-prik + + + + +
+
Loading...
+ + + diff --git a/modules/datumpjeprik/datumpjeprik.js b/modules/datumpjeprik/datumpjeprik.js new file mode 100644 index 0000000..dc56759 --- /dev/null +++ b/modules/datumpjeprik/datumpjeprik.js @@ -0,0 +1,66 @@ +var cmn=require("../$common.js"); +var persist=require("node-persist"), + util=require("util"); + +//Sorry. Prototypes are fun. Using dollars to at least separate these from the built-in methods. +Date.prototype.$dayOfWeek=function(){return (this.getDay()+6)%7;} //monday..sunday = 0..6 +Date.prototype.$startOfDay=function(){return new Date(this-(((this.getHours()*60+this.getMinutes())*60+this.getSeconds())*1000+this.getMilliseconds()));} +Date.prototype.$addDays=function(n){return new Date(this.valueOf()+n*24*3600*1000);} +Date.prototype.$addWeeks=function(n){return new Date(this.valueOf()+n*7*24*3600*1000);} +Date.prototype.$naturalDate=function(){return this.getFullYear()+"-"+("00"+(this.getMonth()+1)).slice(-2)+"-"+("00"+this.getDate()).slice(-2);} + +function diffDays(d1,d2){return ~~(Math.abs(d1-d2)/1000/3600/24);} + +function localDateStringToDate(s){return new Date(s+"T00:00:00");} + + +var periodStart="2015-04-09",periodEnd="2015-07-05", + periodLength=diffDays(localDateStringToDate(periodStart),localDateStringToDate(periodEnd))+1; + +persist=persist.create({ + dir:"persist/datumpjeprik", + continuous:false, + interval:false +}); +persist.initSync(); + +function ensureInitialised(){ + var days; + days=persist.getItem("days"); + if(!days||days.length!=periodLength){ + days=Array.apply(null,new Array(periodLength)).map(function(){return 0;}); + persist.setItemSync("days",days); + } +} +ensureInitialised(); + +module.exports=function(app,io,moddir){ + app.get("/datumpjeprik",function(req,res){ + res.set("Content-Type","text/html"); + res.sendFile(moddir+"/datumpjeprik.html"); + }); + app.get("/datumpjeprik/dates",function(req,res){ + res.set("Content-Type","text/json"); + res.send('{"periodStart":"'+periodStart+'","periodEnd":"'+periodEnd+'"}'); + }); + app.get("/datumpjeprik/days",function(req,res){ + ensureInitialised(); + res.set("Content-Type","text/json"); + res.send(persist.getItem("days")); + }); + app.post("/datumpjeprik/adddays",function(req,res){ + var newdays; + console.log(req.body); + try{ + newdays=JSON.parse(req.body); + if(newdays.length!=periodLength)throw new Error("length mismatch"); + if(!newdays.map(function(v){return typeof v=="boolean";}).reduce(function(a,b){return a&&b;}))throw new Error("not all bools"); + ensureInitialised(); + persist.setItemSync("days",persist.getItem("days").map(function(v,i){return v+newdays[i];})); + res.send("true"); + } catch(e){ + res.send("[false,\""+e.message+"\"]"); + return; + } + }); +}; diff --git a/modules/ip/ip.js b/modules/ip/ip.js new file mode 100644 index 0000000..dec0a98 --- /dev/null +++ b/modules/ip/ip.js @@ -0,0 +1,8 @@ +var cmn=require("../$common.js"), + fs=require("fs"); + +module.exports=function(app,io,moddir){ + app.get("/ip",function(req,res){ + res.send(String(req.socket.remoteAddress)); + }); +}; diff --git a/modules/nlen/English-Dutch-mistranslations.json b/modules/nlen/English-Dutch-mistranslations.json new file mode 100644 index 0000000..dff7229 --- /dev/null +++ b/modules/nlen/English-Dutch-mistranslations.json @@ -0,0 +1,31 @@ +[ +{"nl":"lijge verspreidingen","en":"linux distributions"}, +{"nl":"draadjes","en":"threads"}, +{"nl":"lees-uitvoer-schrijf-cirkel","en":"REPL"}, +{"nl":"ventilator","en":"fan"}, +{"nl":"raamwerk","en":"framework"}, +{"nl":"reagerend","en":"reactive"}, +{"nl":"schoenlipje","en":"bootstrap"}, +{"nl":"materiaal ontwerp","en":"material design"}, +{"nl":"trappende stijl pagina's","en":"CSS"}, +{"nl":"C scherp","en":"C#"}, +{"nl":"Ga","en":"Go"}, +{"nl":"voorkanteinde","en":"front-end"}, +{"nl":"volledige stapel","en":"full-stack"}, +{"nl":"Meteoor, een raamwerk voor reagerende alleen pagina webtoepassingen","en":"Meteor, a framework for single-page web apps"}, +{"nl":"stapeloverloop","en":"stackoverflow"}, +{"nl":"rentijd","en":"runtime"}, +{"nl":"werkelijktijd","en":"realtime"}, +{"nl":"zachte goederen","en":"software"}, +{"nl":"harde goederen","en":"hardware"}, +{"nl":"Hyper-Tekst Markeer-Op Taal","en":"HTML"}, +{"nl":"client","en":"cliënt"}, +{"nl":"serveerder","en":"server"}, +{"nl":"databasis","en":"database"}, +{"nl":"voorhalen","en":"pre-fetch"}, +{"nl":"methoderoepingen","en":"method calls"}, +{"nl":"blauwdruk","en":"template"}, +{"nl":"werktuigen","en":"tools"}, +{"nl":"Toepassing-Programmeer-Tussengezicht","en":"API"}, +{"nl":"Principes van Meteoor\nData op het Snoer. Meteor stuurt geen HTMOT (Hyper Tekst Markeer-Op Taal) over het netwerk. De server stuurt gegevens en laat de cliënt deze weergeven.\nÉén Taal. Meteoor laat je beide de cliënt- en de serveerderdelen van je toepassing in JavaScript schrijven.\nDatabasis Overal. Je kan dezelfde methodes gebruiken om je databasis te bereiken van de cliënt of de serveerder.\nWachttijdcompensatie. Op de cliënt, Meteoor voorhaalt gegevens op en simuleert modellen om het te maken lijken alsof de serveerder methode roepingen instantaan terugkomen.\nVolle-stapel reagerendheid. In Meteoor, werkelijktijd is de standaard. Alle lagen, van databasis tot blauwdruk, vernieuwen zichzelf automatisch wanneer benodigd.\nOmarm het ecosysteem. Meteoor is open bron en integreert met existerende open bron werktuigen en raamwerken.\nEenvoudigheid Evenaart Productiviteit. De beste weg om iets simpel te laten lijken is om het werkelijk simpel te hebben zijn. Meteoor's hoofdfunctionaliteit heeft schone, klassiek-mooie TPT's (Toepassing Programmeer Tussengezichten).","en":"Principles of Meteor\nData on the Wire. Meteor doesn't send HTML over the network. The server sends data and lets the client render it.\nOne Language. Meteor lets you write both the client and the server parts of your application in JavaScript.\nDatabase Everywhere. You can use the same methods to access your database from the client or the server.\nLatency Compensation. On the client, Meteor prefetches data and simulates models to make it look like server method calls return instantly.\nFull Stack Reactivity. In Meteor, realtime is the default. All layers, from database to template, update themselves automatically when necessary.\nEmbrace the Ecosystem. Meteor is open source and integrates with existing open source tools and frameworks.\nSimplicity Equals Productivity. The best way to make something seem simple is to have it actually be simple. Meteor's main functionality has clean, classically beautiful APIs."} +] \ No newline at end of file diff --git a/modules/nlen/nlen.html b/modules/nlen/nlen.html new file mode 100644 index 0000000..dd09e58 --- /dev/null +++ b/modules/nlen/nlen.html @@ -0,0 +1,11 @@ + + + + +NL/EN mistranslations + + +
+
+ + diff --git a/modules/nlen/nlen.js b/modules/nlen/nlen.js new file mode 100644 index 0000000..c988105 --- /dev/null +++ b/modules/nlen/nlen.js @@ -0,0 +1,17 @@ +var cmn=require("../$common.js"), + fs=require("fs"); + +var translations; + +module.exports=function(app,io,moddir){ + translations=eval(String(fs.readFileSync(moddir+"/English-Dutch-mistranslations.json"))); + app.get("/nlen",function(req,res){ + var translation=translations[+new Date()/60000%translations.length|0]; //new translation each minute + res.set('Content-Type', 'text/html'); + res.send( + String(fs.readFileSync(moddir+"/nlen.html")) + .replace("",cmn.simpleHTMLescape(translation.nl)) + .replace("",cmn.simpleHTMLescape(translation.en)) + ); + }); +}; diff --git a/modules/poke/poke.html b/modules/poke/poke.html new file mode 100644 index 0000000..de9ce1f --- /dev/null +++ b/modules/poke/poke.html @@ -0,0 +1,125 @@ + + + + +Poke + + + + + + + + +
+

Users

+
    +
    +

    Notifications

    +
      +
      + + + \ No newline at end of file diff --git a/modules/poke/poke.js b/modules/poke/poke.js new file mode 100644 index 0000000..af0285d --- /dev/null +++ b/modules/poke/poke.js @@ -0,0 +1,47 @@ +var cmn=require("../$common.js"), + fs=require("fs"), + Naampje=require("naampje").name; + +var conns=[]; + +var uniqid=(function(){ + var id=0; + return function(){return id++;}; +})(); + +module.exports=function(app,io,moddir){ + var ioNsp=io.of("/poke"); + app.get("/poke",function(req,res){ + res.sendFile(moddir+"/poke.html"); + }); + ioNsp.on("connection",function(socket){ + var id=uniqid(); + var nick=Naampje(); + var status=""; + socket.emit("reset",null); + socket.emit("self",{id:id,nick:nick}); + conns.forEach(function(c){ + socket.emit("connection add",{id:c.id,nick:c.nick}); + socket.emit("status",{id:c.id,status:c.status}); + }); + ioNsp.emit("connection add",{id:id,nick:nick}); + conns.push({id:id,nick:nick,status:"",socket:socket}); + socket.on("disconnect",function(){ + for(var i=0;i",idx); + var idx2; + var list=[],obj; + var keylist=["timestamp","name","quote"],i; + while(true){ + idx=html.indexOf("row-header-wrapper",idx); if(idx==-1)break; idx+=18; + if(idx>endidx)break; + obj={}; + for(i=0;i",idx); if(idx==-1)break; idx+=1; + idx2=html.indexOf("",idx); if(idx2==-1)break; + obj[keylist[i]]= + html.slice(idx,idx2) + .replace(/<\/?div[^>]*>/g,"") + .replace(/
      /g,"\n") + .replace(/"/g,'"') + .replace(/&/g,"&") + .replace(/&#x([0-9a-f][0-9a-f]);/gi,function(match,p1){ + return String.fromCharCode(parseInt(p1,16)); + }) + .replace(/&#([0-9]{1,3});/g,function(match,p1){ + return String.fromCharCode(parseInt(p1,10)); + }); + idx=idx2+5; + } + if(obj.name=="x"||obj.name=="X")continue; + obj.timestamp=new Date(obj.timestamp); + list.push(obj); + } + return list; +} + +function getquoteslist(cb){ + https.get("https://docs.google.com/spreadsheets/d/1ywrThdscubPOC-gHh_qnFGfuPrtYxTap6UsJBDnt88c/htmlview",function(res){ + var body=""; + res.on("data",function(data){ + body+=data.toString(); + }); + res.on("end",function(){ + cb(parsequoteshtml(body)); + }); + res.on("error",function(err){ + console.log("Error in quotes res:",err); + cb(""); + }); + }).on("error",function(err){ + console.log("Error in quotes https:",err); + cb(""); + }); +} + +module.exports=function(app,io,moddir){ + app.get("/quotes",function(req,res){ + res.set("Content-Type", "text/json"); + getquoteslist(function(obj){ + res.end(JSON.stringify(obj)); + }); + }); +}; diff --git a/modules/subd-krokodil/subd-krokodil.js b/modules/subd-krokodil/subd-krokodil.js new file mode 100644 index 0000000..beabddd --- /dev/null +++ b/modules/subd-krokodil/subd-krokodil.js @@ -0,0 +1,21 @@ +var cmn=require("../$common.js"), + fs=require("fs"), + express=require("express"); + +module.exports=function(app,io,moddir){ + var router=express.Router(); + + router.use(function(req,res,next){ + next(); + }); + + router.get("/",function(req,res){ + res.sendFile(cmn.rootdir+"/web_files/krokodil.jpg"); + }); + + app.use(function(req,res,next){ + if(req.subdomains.length&&req.subdomains[req.subdomains.length-1]=="krokodil"){ + router.handle(req,res,next); + } else next(); + }); +}; diff --git a/modules/ytdl/youtube-dl-Darwin b/modules/ytdl/youtube-dl-Darwin new file mode 100755 index 0000000..97238a0 Binary files /dev/null and b/modules/ytdl/youtube-dl-Darwin differ diff --git a/modules/ytdl/ytdl.html b/modules/ytdl/ytdl.html new file mode 100644 index 0000000..e054b97 --- /dev/null +++ b/modules/ytdl/ytdl.html @@ -0,0 +1,45 @@ + + + + +YTDL + + + +

      YTDL

      +

      This page uses the youtube-dl utility to provide a download link for a given youtube video. It just selects whatever format youtube-dl considers "best"; this is normally video+audio, in the highest quality provided by YouTube. +Enter a link or a video id below:

      +
      +
      +
      
      +
      +
      diff --git a/modules/ytdl/ytdl.js b/modules/ytdl/ytdl.js
      new file mode 100644
      index 0000000..3bbea16
      --- /dev/null
      +++ b/modules/ytdl/ytdl.js
      @@ -0,0 +1,31 @@
      +var cmn=require("../$common.js"),
      +    child_process=require("child_process");
      +
      +module.exports=function(app,io,moddir){
      +	app.param("ytdl_id",function(req,res,next,link){
      +		link=unescape(link);
      +		req.params.ytdl_id=link;
      +		if(/['"\x00-\x1f]/.test(link)){
      +			res.status(400).end("Invalid youtube link or id");
      +			return;
      +		}
      +		next();
      +	});
      +	app.get("/ytdl",function(req,res){
      +		res.sendFile(moddir+"/ytdl.html");
      +	});
      +	app.get("/ytdl/:ytdl_id",function(req,res){
      +		var link=req.params.ytdl_id;
      +		var cp=child_process.execFile("/usr/bin/env",["youtube-dl","-gf","best",link],{},function(err,stdout,stderr){
      +			if(err){
      +				//console.log(err);
      +				res.status(404);
      +				res.set("Content-Type","text/plain");
      +				res.end("Youtube video id not found\n\n"+stdout+"\n\n"+stderr);
      +				return;
      +			}
      +			res.set("Content-Type","text/plain");
      +			res.send(stdout);
      +		});
      +	});
      +};
      -- 
      cgit v1.2.3-70-g09d2