.
This commit is contained in:
parent
a202ae2e69
commit
29329702da
34
debug/trigger.mjs
Normal file
34
debug/trigger.mjs
Normal file
|
@ -0,0 +1,34 @@
|
|||
import { promises as fs } from "fs";
|
||||
|
||||
(async () => {
|
||||
const _args = process.argv.slice(2);
|
||||
const _e = {
|
||||
network: "console",
|
||||
message: _args.join(" "),
|
||||
args: _args.slice(1),
|
||||
channel: "console",
|
||||
user: {
|
||||
prefix: "console!console@console",
|
||||
nick: "console",
|
||||
username: "console",
|
||||
account: "console"
|
||||
},
|
||||
reply: (...args) => console.log(args),
|
||||
replyAction: (...args) => console.log(args),
|
||||
replyNotice: (...args) => console.log(args)
|
||||
};
|
||||
|
||||
const trigger = (await Promise.all((await fs.readdir("./src/inc/trigger"))
|
||||
.filter(f => f.endsWith(".mjs"))
|
||||
.map(async t => await (await import(`../src/inc/trigger/${t}`)).default())
|
||||
)).filter(t => t[0].call.test(_e.message)).map(t => ({ name: t[0].name, f: t[0].f }));
|
||||
|
||||
try {
|
||||
if(trigger.length === 0)
|
||||
return console.error("no matches");
|
||||
console.log(`triggered > ${trigger[0].name} (${_e.message})`);
|
||||
await trigger[0].f(_e);
|
||||
} catch(err) {
|
||||
console.error(err);
|
||||
}
|
||||
})();
|
107
package-lock.json
generated
107
package-lock.json
generated
|
@ -10,38 +10,18 @@
|
|||
"integrity": "sha512-wE2v81i4C4Ol09RtsWFAqg3BUitWbHSpSlIo+bNdsCJijO9sjme+zm+73ZMCa/qMC8UEERxzGbvmr1cffo2SiQ=="
|
||||
},
|
||||
"@types/node": {
|
||||
"version": "13.9.8",
|
||||
"resolved": "https://registry.npmjs.org/@types/node/-/node-13.9.8.tgz",
|
||||
"integrity": "sha512-1WgO8hsyHynlx7nhP1kr0OFzsgKz5XDQL+Lfc3b1Q3qIln/n8cKD4m09NJ0+P1Rq7Zgnc7N0+SsMnoD1rEb0kA=="
|
||||
},
|
||||
"amdefine": {
|
||||
"version": "1.0.1",
|
||||
"resolved": "https://registry.npmjs.org/amdefine/-/amdefine-1.0.1.tgz",
|
||||
"integrity": "sha1-SlKCrBZHKek2Gbz9OtFR+BfOkfU="
|
||||
},
|
||||
"async": {
|
||||
"version": "0.2.10",
|
||||
"resolved": "https://registry.npmjs.org/async/-/async-0.2.10.tgz",
|
||||
"integrity": "sha1-trvgsGdLnXGXCMo43owjfLUmw9E="
|
||||
},
|
||||
"camelcase": {
|
||||
"version": "1.2.1",
|
||||
"resolved": "https://registry.npmjs.org/camelcase/-/camelcase-1.2.1.tgz",
|
||||
"integrity": "sha1-m7UwTS4LVmmLLHWLCKPqqdqlijk="
|
||||
"version": "13.11.0",
|
||||
"resolved": "https://registry.npmjs.org/@types/node/-/node-13.11.0.tgz",
|
||||
"integrity": "sha512-uM4mnmsIIPK/yeO+42F2RQhGUIs39K2RFmugcJANppXe6J1nvH87PvzPZYpza7Xhhs8Yn9yIAVdLZ84z61+0xQ=="
|
||||
},
|
||||
"cuffeo": {
|
||||
"version": "1.0.6",
|
||||
"resolved": "https://registry.npmjs.org/cuffeo/-/cuffeo-1.0.6.tgz",
|
||||
"integrity": "sha512-TdrkkDM4uR/iTEtazfxbmLUXoNB3NLC/RMgpWVUQC8j2uOiaLl7U7agdLdxfJq4uEt56cJUftqH9Tb3BofslNg==",
|
||||
"version": "1.0.6-1",
|
||||
"resolved": "https://registry.npmjs.org/cuffeo/-/cuffeo-1.0.6-1.tgz",
|
||||
"integrity": "sha512-r7MCG7rIuG86leo4aB73YEkl7UWAGprd2A/9xy4iZmrbMepIFaCgHOn7SC6wemPbS4LRXQAgqvV9a6PCyHaCfg==",
|
||||
"requires": {
|
||||
"flumm-fetch-cookies": "^1.3.5"
|
||||
}
|
||||
},
|
||||
"decamelize": {
|
||||
"version": "1.2.0",
|
||||
"resolved": "https://registry.npmjs.org/decamelize/-/decamelize-1.2.0.tgz",
|
||||
"integrity": "sha1-9lNNFRSCabIDUue+4m9QH5oZEpA="
|
||||
},
|
||||
"denque": {
|
||||
"version": "1.4.1",
|
||||
"resolved": "https://registry.npmjs.org/denque/-/denque-1.4.1.tgz",
|
||||
|
@ -86,11 +66,6 @@
|
|||
"moment-timezone": "^0.5.27"
|
||||
}
|
||||
},
|
||||
"minimist": {
|
||||
"version": "0.0.10",
|
||||
"resolved": "https://registry.npmjs.org/minimist/-/minimist-0.0.10.tgz",
|
||||
"integrity": "sha1-3j+YVD2/lggr5IrRoMfNqDYwHc8="
|
||||
},
|
||||
"moment": {
|
||||
"version": "2.24.0",
|
||||
"resolved": "https://registry.npmjs.org/moment/-/moment-2.24.0.tgz",
|
||||
|
@ -104,80 +79,10 @@
|
|||
"moment": ">= 2.9.0"
|
||||
}
|
||||
},
|
||||
"optimist": {
|
||||
"version": "0.6.1",
|
||||
"resolved": "https://registry.npmjs.org/optimist/-/optimist-0.6.1.tgz",
|
||||
"integrity": "sha1-2j6nRob6IaGaERwybpDrFaAZZoY=",
|
||||
"requires": {
|
||||
"minimist": "~0.0.1",
|
||||
"wordwrap": "~0.0.2"
|
||||
}
|
||||
},
|
||||
"safer-buffer": {
|
||||
"version": "2.1.2",
|
||||
"resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz",
|
||||
"integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg=="
|
||||
},
|
||||
"source-map": {
|
||||
"version": "0.1.34",
|
||||
"resolved": "https://registry.npmjs.org/source-map/-/source-map-0.1.34.tgz",
|
||||
"integrity": "sha1-p8/omux7FoLDsZjQrPtH19CQVms=",
|
||||
"requires": {
|
||||
"amdefine": ">=0.0.4"
|
||||
}
|
||||
},
|
||||
"swig": {
|
||||
"version": "1.4.2",
|
||||
"resolved": "https://registry.npmjs.org/swig/-/swig-1.4.2.tgz",
|
||||
"integrity": "sha1-QIXKBFM2kQS11IPihBs5t64aq6U=",
|
||||
"requires": {
|
||||
"optimist": "~0.6",
|
||||
"uglify-js": "~2.4"
|
||||
}
|
||||
},
|
||||
"uglify-js": {
|
||||
"version": "2.4.24",
|
||||
"resolved": "https://registry.npmjs.org/uglify-js/-/uglify-js-2.4.24.tgz",
|
||||
"integrity": "sha1-+tV1XB4Vd2WLsG/5q25UjJW+vW4=",
|
||||
"requires": {
|
||||
"async": "~0.2.6",
|
||||
"source-map": "0.1.34",
|
||||
"uglify-to-browserify": "~1.0.0",
|
||||
"yargs": "~3.5.4"
|
||||
}
|
||||
},
|
||||
"uglify-to-browserify": {
|
||||
"version": "1.0.2",
|
||||
"resolved": "https://registry.npmjs.org/uglify-to-browserify/-/uglify-to-browserify-1.0.2.tgz",
|
||||
"integrity": "sha1-bgkk1r2mta/jSeOabWMoUKD4grc="
|
||||
},
|
||||
"window-size": {
|
||||
"version": "0.1.0",
|
||||
"resolved": "https://registry.npmjs.org/window-size/-/window-size-0.1.0.tgz",
|
||||
"integrity": "sha1-VDjNLqk7IC76Ohn+iIeu58lPnJ0="
|
||||
},
|
||||
"wordwrap": {
|
||||
"version": "0.0.3",
|
||||
"resolved": "https://registry.npmjs.org/wordwrap/-/wordwrap-0.0.3.tgz",
|
||||
"integrity": "sha1-o9XabNXAvAAI03I0u68b7WMFkQc="
|
||||
},
|
||||
"yargs": {
|
||||
"version": "3.5.4",
|
||||
"resolved": "https://registry.npmjs.org/yargs/-/yargs-3.5.4.tgz",
|
||||
"integrity": "sha1-2K/49mXpTDS9JZvevRv68N3TU2E=",
|
||||
"requires": {
|
||||
"camelcase": "^1.0.2",
|
||||
"decamelize": "^1.0.0",
|
||||
"window-size": "0.1.0",
|
||||
"wordwrap": "0.0.2"
|
||||
},
|
||||
"dependencies": {
|
||||
"wordwrap": {
|
||||
"version": "0.0.2",
|
||||
"resolved": "https://registry.npmjs.org/wordwrap/-/wordwrap-0.0.2.tgz",
|
||||
"integrity": "sha1-t5Zpu0LstAn4PVg8rVLKF+qhZD8="
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -4,14 +4,14 @@
|
|||
"description": "f0ck, kennste?",
|
||||
"main": "index.mjs",
|
||||
"scripts": {
|
||||
"start": "node --experimental-json-modules --harmony-optional-chaining src/index.mjs"
|
||||
"start": "node --experimental-json-modules --harmony-optional-chaining src/index.mjs",
|
||||
"trigger": "node --experimental-json-modules --harmony-optional-chaining debug/trigger.mjs"
|
||||
},
|
||||
"author": "Flummi",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"cuffeo": "^1.0.6-1",
|
||||
"flumm-fetch-cookies": "^1.3.5",
|
||||
"mariadb": "^2.3.1",
|
||||
"swig": "^1.4.2"
|
||||
"mariadb": "^2.3.1"
|
||||
}
|
||||
}
|
||||
|
|
55
public/s/js/item.js
Normal file
55
public/s/js/item.js
Normal file
|
@ -0,0 +1,55 @@
|
|||
const epochs = [
|
||||
["year", 31536000],
|
||||
["month", 2592000],
|
||||
["day", 86400],
|
||||
["hour", 3600],
|
||||
["minute", 60],
|
||||
["second", 1]
|
||||
];
|
||||
const getDuration = timeAgoInSeconds => {
|
||||
for(let [name, seconds] of epochs) {
|
||||
const interval = ~~(timeAgoInSeconds / seconds);
|
||||
if(interval >= 1) return {
|
||||
interval: interval,
|
||||
epoch: name
|
||||
};
|
||||
}
|
||||
};
|
||||
const timeAgo = date => {
|
||||
const { interval, epoch } = getDuration(~~((new Date() - new Date(date)) / 1000));
|
||||
return `${interval} ${epoch}${interval === 1 ? "" : "s"} ago`;
|
||||
};
|
||||
const clickOnElementBinding = selector => () => (elem = document.querySelector(selector))?elem.click():null;
|
||||
const keybindings = {
|
||||
"ArrowLeft": clickOnElementBinding("#next"),
|
||||
"ArrowRight": clickOnElementBinding("#prev"),
|
||||
"r": clickOnElementBinding("#random")
|
||||
};
|
||||
|
||||
(() => {
|
||||
if(video = document.querySelector(".video-js")) {
|
||||
const vid1 = videojs(video);
|
||||
vid1.persistvolume({
|
||||
namespace: "f0ck"
|
||||
});
|
||||
if(vid1.autoplay() && !vid1.paused() && vid1.hasClass("vjs-paused")) {
|
||||
vid1.pause();
|
||||
vid1.play();
|
||||
}
|
||||
}
|
||||
|
||||
document.querySelectorAll("time.timeago").forEach(e => e.innerHTML = timeAgo(e.title));
|
||||
|
||||
document.addEventListener("keydown", e => {
|
||||
if(e.key in keybindings) {
|
||||
e.preventDefault();
|
||||
keybindings[e.key]();
|
||||
}
|
||||
});
|
||||
|
||||
if(f0ckimage = document.querySelector("#f0ck-image"))
|
||||
f0ckimage.addEventListener("click", e => {
|
||||
e.preventDefault();
|
||||
f0ckimage.hasAttribute("style")?f0ckimage.removeAttribute("style"):f0ckimage.setAttribute("style", "max-height: unset;");
|
||||
});
|
||||
})();
|
|
@ -1,25 +0,0 @@
|
|||
const clickOnElementBinding = selector => () => (elem = document.querySelector(selector))?elem.click():null;
|
||||
|
||||
const keybindings = {
|
||||
"ArrowLeft": clickOnElementBinding("#next"),
|
||||
"ArrowRight": clickOnElementBinding("#prev"),
|
||||
"r": clickOnElementBinding("#random")
|
||||
};
|
||||
|
||||
(() => {
|
||||
document.addEventListener("keydown", e => {
|
||||
if(e.key in keybindings) {
|
||||
e.preventDefault();
|
||||
keybindings[e.key]();
|
||||
}
|
||||
});
|
||||
|
||||
const f0ckimage = document.querySelector("#f0ck-image");
|
||||
if(f0ckimage) {
|
||||
f0ckimage.addEventListener("click", e => {
|
||||
e.preventDefault();
|
||||
f0ckimage.hasAttribute("style")?f0ckimage.removeAttribute("style"):f0ckimage.setAttribute("style", "max-height: unset;");
|
||||
});
|
||||
}
|
||||
})();
|
||||
//sorry, jQuery ist dumm :--D sorry sirx, dass ich wonnes Kot auskommentiert habe
|
|
@ -1,9 +1,10 @@
|
|||
import router from "../router.mjs";
|
||||
import cfg from "../../../config.json";
|
||||
import fs from "fs";
|
||||
import sql from "../sql.mjs";
|
||||
import swig from "swig";
|
||||
import url from "url";
|
||||
import sql from "../sql.mjs";
|
||||
import lib from "../lib.mjs";
|
||||
import tpl from "../tpl.mjs";
|
||||
|
||||
const templates = {
|
||||
contact: fs.readFileSync("./views/contact.html", "utf-8"),
|
||||
|
@ -21,7 +22,7 @@ router.get("/", async (req, res) => {
|
|||
};
|
||||
|
||||
res.reply({
|
||||
body: swig.compile(templates.index)(data)
|
||||
body: tpl.render(templates.index, data)
|
||||
});
|
||||
});
|
||||
|
||||
|
@ -74,7 +75,7 @@ router.get(/^\/([0-9]+)$/, async (req, res) => {
|
|||
data.thumb = `${cfg.websrv.paths.thumbnails}/${e.id}.png`;
|
||||
data.dest = `${cfg.websrv.paths.images}/${e.dest}`;
|
||||
data.mime = e.mime;
|
||||
data.size = e.size;//lib.formatSize(e.size);
|
||||
data.size = lib.formatSize(e.size);
|
||||
data.userchannel = e.userchannel;
|
||||
data.usernetwork = e.usernetwork;
|
||||
data.timestamp = new Date(e.stamp * 1000).toISOString();
|
||||
|
@ -84,7 +85,7 @@ router.get(/^\/([0-9]+)$/, async (req, res) => {
|
|||
data.prev = query[2][0].id;
|
||||
}
|
||||
res.reply({
|
||||
body: swig.compile(templates.item)(data)
|
||||
body: tpl.render(templates.item, data)
|
||||
});
|
||||
});
|
||||
|
||||
|
|
30
src/inc/tpl.mjs
Normal file
30
src/inc/tpl.mjs
Normal file
|
@ -0,0 +1,30 @@
|
|||
export default new class {
|
||||
syntax = [
|
||||
[ "each", t => `util.forEach(${t.slice(4).trim()},($value,$key)=>{` ],
|
||||
[ "/each", () => "});" ],
|
||||
[ "if", t => `if(${t.slice(2).trim()}){` ],
|
||||
[ "elseif", t => `}else if(${t.slice(6).trim()}){` ],
|
||||
[ "else", () => "}else{" ],
|
||||
[ "/if", () => "}" ],
|
||||
[ "=", t => `html+=${t.slice(1).trim()};` ]
|
||||
];
|
||||
forEach(o, f) {
|
||||
if(Array.isArray(o))
|
||||
o.forEach(f);
|
||||
else if(typeof o === "object")
|
||||
Object.keys(o).forEach(k => f.call(null, o[k], k));
|
||||
else
|
||||
throw new Error(`${o} is not a iterable object`);
|
||||
}
|
||||
render(tpl, data) {
|
||||
return new Function("util", "data", "let html = \"\";with(data){"
|
||||
+ tpl.trim().replace(/[\n\r]/g, "").split(/{{\s*([^}]+)\s*}}/).filter(Boolean).map(t => {
|
||||
for(let i = 0; i < this.syntax.length; i++)
|
||||
if(t.indexOf(this.syntax[i][0]) === 0)
|
||||
return this.syntax[i][1](t);
|
||||
return `html+='${t}';`;
|
||||
})
|
||||
.join`` + "}return html.trim().replace(/>[\\n\\r\\s]*?</g, '><')")
|
||||
.bind(null, { forEach: this.forEach })(data);
|
||||
}
|
||||
};
|
|
@ -18,12 +18,22 @@ export default async bot => {
|
|||
t: await fs.readdir("./public/t")
|
||||
};
|
||||
const sizes = {
|
||||
b: (await Promise.all(dirs.b.map(async file => (await fs.stat(`./public/b/${file}`)).size))).reduce((a, b) => b + a),
|
||||
t: (await Promise.all(dirs.t.map(async file => (await fs.stat(`./public/t/${file}`)).size))).reduce((a, b) => b + a),
|
||||
b: lib.formatSize((await Promise.all(dirs.b.map(async file => (await fs.stat(`./public/b/${file}`)).size))).reduce((a, b) => b + a)),
|
||||
t: lib.formatSize((await Promise.all(dirs.t.map(async file => (await fs.stat(`./public/t/${file}`)).size))).reduce((a, b) => b + a)),
|
||||
};
|
||||
return e.reply(`${dirs.b.length} f0cks: ${sizes.b}, ${dirs.t.length} thumbnails: ${sizes.t}`);
|
||||
case "limit":
|
||||
return e.reply(`up to ${lib.formatSize(cfg.main.maxfilesize)} (${lib.formatSize(cfg.main.maxfilesize * 2.5)} for admins)`);
|
||||
case "thumb":
|
||||
const rows = await sql.query("select id from items");
|
||||
const dir = (await fs.readdir("./public/t")).filter(d => d.endsWith(".png")).map(e => +e.split(".")[0]);
|
||||
|
||||
const tmp = [];
|
||||
for(let row of rows) {
|
||||
!dir.includes(row.id) ? tmp.push(row.id) : null;
|
||||
}
|
||||
e.reply(`${tmp.length}, ${rows.length}, ${dir.length}`);
|
||||
break;
|
||||
default:
|
||||
return e.reply("lul");
|
||||
}
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
<!DOCTYPE f0ck>
|
||||
<!doctype f0ck>
|
||||
<html>
|
||||
<head>
|
||||
<title>f0ck!</title>
|
||||
|
@ -29,14 +29,14 @@
|
|||
</nav>
|
||||
|
||||
<div class="container-fluid">
|
||||
<ul id="posts" data-last="{{ last }}">
|
||||
{% for item in items %}
|
||||
<li class="post"><a href="/{{ item.id }}" title="{{ item.mime }}">
|
||||
<img class="thumb" src="/t/{{ item.id }}.png" />
|
||||
<span class="item-mime">{{ item.mime }}</span>
|
||||
<ul id="posts" data-last="{{=last}}">
|
||||
{{each items}}
|
||||
<li class="post"><a href="/{{=$value.id}}" title="{{=$value.mime}}">
|
||||
<img class="thumb" src="/t/{{=$value.id}}.png" />
|
||||
<span class="item-mime">{{=$value.mime}}</span>
|
||||
</a>
|
||||
</li>
|
||||
{% endfor %}
|
||||
{{/each}}
|
||||
</ul>
|
||||
</div>
|
||||
<script src="./s/js/scroller.js"></script>
|
||||
|
|
108
views/item.html
108
views/item.html
|
@ -1,7 +1,7 @@
|
|||
<!doctype f0ck>
|
||||
<html>
|
||||
<head>
|
||||
<title>{{ id }} - f0ck.me</title>
|
||||
<title>{{=id}} - f0ck.me</title>
|
||||
<link rel="stylesheet" type="text/css" href="./s/css/video-js.min.css" />
|
||||
<link rel="stylesheet" type="text/css" href="./s/css/vsg-skin.css" />
|
||||
<link rel="stylesheet" type="text/css" href="./s/css/bootstrap.css">
|
||||
|
@ -9,9 +9,9 @@
|
|||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
<link rel="icon" type="image/png" href="./s/img/favicon.png" />
|
||||
<meta property="og:site_name" content="f0ck.me" />
|
||||
<meta property="og:description" content="f0cked by {{ username }}" />
|
||||
<meta name="Description" content="f0cked by {{ username }}" />
|
||||
<meta property="og:image" content="{{ thumbnail }}" />
|
||||
<meta property="og:description" content="f0cked by {{=username}}" />
|
||||
<meta name="Description" content="f0cked by {{=username}}" />
|
||||
<meta property="og:image" content="{{=thumbnail}}" />
|
||||
<meta charset="utf-8" />
|
||||
</head>
|
||||
<body>
|
||||
|
@ -40,105 +40,49 @@
|
|||
<div class="content">
|
||||
|
||||
<div class="next-post">
|
||||
{% if next != null %}
|
||||
<a id="next" href="/{{ next }}">«</a>
|
||||
{% else %}
|
||||
{{if next}}
|
||||
<a id="next" href="/{{=next}}">«</a>
|
||||
{{else}}
|
||||
<a id="next" href="#" style="color: #ccc !important;">«</a>
|
||||
{% endif %}
|
||||
{{/if}}
|
||||
</div>
|
||||
|
||||
<div class="media-object">
|
||||
{% if item == "video" %}
|
||||
{{if item === "video"}}
|
||||
<div class="embed-responsive embed-responsive-16by9">
|
||||
<video id="my-video" class="video-js embed-responsive-item" width="640" height="360" src="{{ dest }}" preload="auto" autoplay controls loop data-setup="{}"></video>
|
||||
<video id="my-video" class="video-js embed-responsive-item" width="640" height="360" src="{{=dest}}" preload="auto" autoplay controls loop data-setup="{}"></video>
|
||||
</div>
|
||||
{% elseif item == "audio" %}
|
||||
|
||||
{% if thumb != null %}
|
||||
<div>
|
||||
|
||||
<!-- <img src="{{ thumb }}" /><br /> -->
|
||||
|
||||
{% endif %}
|
||||
{{elseif item === "audio"}}
|
||||
<div class="embed-responsive embed-responsive-16by9">
|
||||
<audio id="my-video" class="embed-responsive-item video-js audiojs" autoplay controls loop src="{{ dest }}" data-setup="{}" poster="{% if thumb !== null %}{{ thumb }}{% else %}/s/200.gif{% endif %}" type="audio/mp3" ></audio>
|
||||
<audio id="my-video" class="embed-responsive-item video-js audiojs" autoplay controls loop src="{{=dest}}" data-setup="{}" poster="{{if thumb}}{{=thumb}}{{else}}/s/200.gif{{/if}}" type="audio/mp3" ></audio>
|
||||
</div>
|
||||
{% if thumb != null %}
|
||||
</div>
|
||||
|
||||
{% endif %}
|
||||
{% elseif item == "image" %}
|
||||
<a href="{{ dest }}" id="elfe" target="_blank"><img id="f0ck-image" src="{{ dest }}" /></a>
|
||||
{% else %}
|
||||
|
||||
{{elseif item === "image"}}
|
||||
<a href="{{=dest}}" id="elfe" target="_blank"><img id="f0ck-image" src="{{=dest}}" /></a>
|
||||
{{else}}
|
||||
<h1>404 - Not f0cked</h1>
|
||||
{% endif %}
|
||||
{{/if}}
|
||||
</div>
|
||||
|
||||
<div class="previous-post">
|
||||
{% if prev != null %}
|
||||
<a id="prev" href="/{{ prev }}">»</a>
|
||||
{% else %}
|
||||
{{if prev}}
|
||||
<a id="prev" href="/{{=prev}}">»</a>
|
||||
{{else}}
|
||||
<a id="prev" href="#" style="color: #ccc !important;">»</a>
|
||||
{% endif %}
|
||||
{{/if}}
|
||||
</div>
|
||||
|
||||
</div>
|
||||
<div class="metadata">
|
||||
<span class="badge badge-dark"><a href="/{{ id }}" class="id-link">{{ id }} </a> by {{ username }}</span>
|
||||
<span class="badge badge-dark">{{ usernetwork }} / {{ userchannel }}</span>
|
||||
<span class="badge badge-dark"><a id="post_source" href="{{ srcurl }}" target="_blank">{{ src }}</a></span>
|
||||
<span class="badge badge-dark">{{ size }}</span>
|
||||
<span class="badge badge-dark"><time class="timeago" title="{{ timestamp }}" datetime="{{ timestamp }}"> </time></span>
|
||||
<span class="badge badge-dark"><a href="/{{=id}}" class="id-link">{{=id}} </a> by {{=username}}</span>
|
||||
<span class="badge badge-dark">{{=usernetwork}} / {{=userchannel}}</span>
|
||||
<span class="badge badge-dark"><a id="post_source" href="{{=srcurl}}" target="_blank">{{=src}}</a></span>
|
||||
<span class="badge badge-dark">{{=size}}</span>
|
||||
<span class="badge badge-dark"><time class="timeago" title="{{=timestamp}}" datetime="{{=timestamp}}"> </time></span>
|
||||
<span class="badge badge-dark" id="themes"></span>
|
||||
</div>
|
||||
</div>
|
||||
<script src="./s/js/shit.js"></script>
|
||||
<script src="./s/js/theme.js"></script>
|
||||
<script src="./s/js/video.min.js"></script>
|
||||
<script src="./s/js/videojs.persistvolume.js"></script>
|
||||
<script>
|
||||
(function() {
|
||||
let video = document.querySelector(".video-js");
|
||||
if(!video)
|
||||
return;
|
||||
var vid1 = videojs(video);
|
||||
vid1.persistvolume({
|
||||
namespace: "f0ck"
|
||||
});
|
||||
if(vid1.autoplay() && !vid1.paused() && vid1.hasClass('vjs-paused')) {
|
||||
vid1.pause();
|
||||
vid1.play();
|
||||
}
|
||||
})();
|
||||
const epochs = [
|
||||
["year", 31536000],
|
||||
["month", 2592000],
|
||||
["day", 86400],
|
||||
["hour", 3600],
|
||||
["minute", 60],
|
||||
["second", 1]
|
||||
];
|
||||
const getDuration = timeAgoInSeconds => {
|
||||
for(let [name, seconds] of epochs) {
|
||||
const interval = ~~(timeAgoInSeconds / seconds);
|
||||
if (interval >= 1) {
|
||||
return {
|
||||
interval: interval,
|
||||
epoch: name
|
||||
};
|
||||
}
|
||||
}
|
||||
};
|
||||
const timeAgo = date => {
|
||||
const timeAgoInSeconds = ~~((new Date() - new Date(date)) / 1000);
|
||||
const {interval, epoch} = getDuration(timeAgoInSeconds);
|
||||
const suffix = interval === 1 ? "" : "s";
|
||||
return `${interval} ${epoch}${suffix} ago`;
|
||||
};
|
||||
(() => {
|
||||
document.querySelectorAll("time.timeago").forEach(e => e.innerHTML = timeAgo(e.title));
|
||||
})();
|
||||
</script>
|
||||
<script src="./s/js/item.js"></script>
|
||||
</body>
|
||||
</html>
|
||||
|
|
Loading…
Reference in New Issue
Block a user