housekeeping

This commit is contained in:
waveringana 2022-12-02 13:59:50 +00:00
parent 462d388b15
commit eca5e3c841
31 changed files with 1259 additions and 1259 deletions

View file

@ -91,3 +91,4 @@ jobs:
labels: ${{ steps.meta.outputs.labels }} labels: ${{ steps.meta.outputs.labels }}
cache-from: type=gha cache-from: type=gha
cache-to: type=gha,mode=max cache-to: type=gha,mode=max
file: {context}/docker/Dockerfile

View file

@ -11,5 +11,5 @@ jobs:
- name: Cypress run - name: Cypress run
uses: cypress-io/github-action@v4 uses: cypress-io/github-action@v4
with: with:
build: node db.js build: node app/db.js
start: npm start start: npm start

View file

@ -13,11 +13,11 @@ Upcoming Features:
Source: Source:
```Bash ```Bash
EBPASS=changeme EBPASS=changeme
EBPORT=4000 EBPORT=3000
EBAPI_KEY=changeme #ShareX support EBAPI_KEY=changeme #ShareX support
$ npm install $ npm install
$ node db.js $ node app/db.js
$ npm start $ npm start
``` ```
Default username is admin with the password being whatever EBPASS is Default username is admin with the password being whatever EBPASS is
@ -49,7 +49,7 @@ JSON
Docker config Docker config
``` ```
docker run -d -p "4000:4000" -e EBPORT=4000 -e EBPASS=changeme -e EBAPI_KEY=changeme ghcr.io/waveringana/embedder:1.7.1 docker run -d -p "3000:3000" -e EBPORT=3000 -e EBPASS=changeme -e EBAPI_KEY=changeme ghcr.io/waveringana/embedder:1.7.1
``` ```
Docker Compose Docker Compose

View file

@ -1,31 +1,31 @@
{ {
"env": { "env": {
"node": true, "node": true,
"commonjs": true, "commonjs": true,
"es2021": true "es2021": true
}, },
"extends": "eslint:recommended", "extends": "eslint:recommended",
"overrides": [ "overrides": [
], ],
"parserOptions": { "parserOptions": {
"ecmaVersion": "latest" "ecmaVersion": "latest"
}, },
"rules": { "rules": {
"indent": [ "indent": [
"error", "error",
"tab" "tab"
], ],
"linebreak-style": [ "linebreak-style": [
"error", "error",
"unix" "unix"
], ],
"quotes": [ "quotes": [
"error", "error",
"double" "double"
], ],
"semi": [ "semi": [
"error", "error",
"always" "always"
] ]
} }
} }

View file

@ -13,7 +13,7 @@ const path = require("path");
const authRouter = require("./routes/auth"); const authRouter = require("./routes/auth");
const indexRouter = require("./routes/index"); const indexRouter = require("./routes/index");
const db = require("./db"); const db = require("./db").db;
let app = express(); let app = express();
let server = http.createServer(app); let server = http.createServer(app);

View file

@ -10,25 +10,28 @@ let db = new sqlite3.Database("./var/db/media.db");
db.serialize(function() { db.serialize(function() {
// create the database schema for the todos app // create the database schema for the todos app
db.run("CREATE TABLE IF NOT EXISTS users ( \ db.run("CREATE TABLE IF NOT EXISTS users ( \
id INTEGER PRIMARY KEY, \ id INTEGER PRIMARY KEY, \
username TEXT UNIQUE, \ username TEXT UNIQUE, \
hashed_password BLOB, \ hashed_password BLOB, \
salt BLOB \ salt BLOB \
)"); )");
db.run("CREATE TABLE IF NOT EXISTS media ( \ db.run("CREATE TABLE IF NOT EXISTS media ( \
id INTEGER PRIMARY KEY, \ id INTEGER PRIMARY KEY, \
path TEXT NOT NULL, \ path TEXT NOT NULL, \
expire INTEGER \ expire INTEGER \
)"); )");
// create an initial user (username: alice, password: letmein) createUser("admin", process.env.EBPASS || "changeme");
var salt = crypto.randomBytes(16);
db.run("INSERT OR IGNORE INTO users (username, hashed_password, salt) VALUES (?, ?, ?)", [
"admin",
crypto.pbkdf2Sync(process.env.EBPASS || "changeme", salt, 310000, 32, "sha256"),
salt
]);
}); });
module.exports = db; function createUser(username, password) {
var salt = crypto.randomBytes(16);
db.run("INSERT OR IGNORE INTO users (username, hashed_password, salt) VALUES (?, ?, ?)", [
username,
crypto.pbkdf2Sync(password, salt, 310000, 32, "sha256"),
salt
]);
}
module.exports = {db: db, createUser: createUser};

View file

Before

Width:  |  Height:  |  Size: 70 KiB

After

Width:  |  Height:  |  Size: 70 KiB

Before After
Before After

View file

Before

Width:  |  Height:  |  Size: 400 KiB

After

Width:  |  Height:  |  Size: 400 KiB

Before After
Before After

View file

Before

Width:  |  Height:  |  Size: 63 KiB

After

Width:  |  Height:  |  Size: 63 KiB

Before After
Before After

View file

@ -1,116 +1,116 @@
.nav { .nav {
position: absolute; position: absolute;
top: -130px; top: -130px;
right: 0; right: 0;
} }
.nav ul { .nav ul {
margin: 0; margin: 0;
list-style: none; list-style: none;
text-align: center; text-align: center;
} }
.nav li { .nav li {
display: inline-block; display: inline-block;
height: 40px; height: 40px;
margin-left: 12px; margin-left: 12px;
font-size: 14px; font-size: 14px;
font-weight: 400; font-weight: 400;
line-height: 40px; line-height: 40px;
} }
.nav a { .nav a {
display: block; display: block;
color: inherit; color: inherit;
text-decoration: none; text-decoration: none;
} }
.nav a:hover { .nav a:hover {
border-bottom: 1px solid #DB7676; border-bottom: 1px solid #DB7676;
} }
.nav button { .nav button {
height: 40px; height: 40px;
} }
.nav button:hover { .nav button:hover {
border-bottom: 1px solid #DB7676; border-bottom: 1px solid #DB7676;
cursor: pointer; cursor: pointer;
} }
/* background image by Cole Bemis <https://feathericons.com> */ /* background image by Cole Bemis <https://feathericons.com> */
.nav .user { .nav .user {
padding-left: 20px; padding-left: 20px;
background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='18' height='18' viewBox='0 0 24 24' fill='none' stroke='currentColor' stroke-width='2' stroke-linecap='round' stroke-linejoin='round' class='feather feather-user'%3E%3Cpath d='M20 21v-2a4 4 0 0 0-4-4H8a4 4 0 0 0-4 4v2'%3E%3C/path%3E%3Ccircle cx='12' cy='7' r='4'%3E%3C/circle%3E%3C/svg%3E"); background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='18' height='18' viewBox='0 0 24 24' fill='none' stroke='currentColor' stroke-width='2' stroke-linecap='round' stroke-linejoin='round' class='feather feather-user'%3E%3Cpath d='M20 21v-2a4 4 0 0 0-4-4H8a4 4 0 0 0-4 4v2'%3E%3C/path%3E%3Ccircle cx='12' cy='7' r='4'%3E%3C/circle%3E%3C/svg%3E");
background-repeat: no-repeat; background-repeat: no-repeat;
background-position: center left; background-position: center left;
} }
/* background image by Cole Bemis <https://feathericons.com> */ /* background image by Cole Bemis <https://feathericons.com> */
.nav .logout { .nav .logout {
padding-left: 20px; padding-left: 20px;
background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='18' height='18' viewBox='0 0 24 24' fill='none' stroke='currentColor' stroke-width='2' stroke-linecap='round' stroke-linejoin='round' class='feather feather-log-out'%3E%3Cpath d='M9 21H5a2 2 0 0 1-2-2V5a2 2 0 0 1 2-2h4'%3E%3C/path%3E%3Cpolyline points='16 17 21 12 16 7'%3E%3C/polyline%3E%3Cline x1='21' y1='12' x2='9' y2='12'%3E%3C/line%3E%3C/svg%3E%0A"); background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='18' height='18' viewBox='0 0 24 24' fill='none' stroke='currentColor' stroke-width='2' stroke-linecap='round' stroke-linejoin='round' class='feather feather-log-out'%3E%3Cpath d='M9 21H5a2 2 0 0 1-2-2V5a2 2 0 0 1 2-2h4'%3E%3C/path%3E%3Cpolyline points='16 17 21 12 16 7'%3E%3C/polyline%3E%3Cline x1='21' y1='12' x2='9' y2='12'%3E%3C/line%3E%3C/svg%3E%0A");
background-repeat: no-repeat; background-repeat: no-repeat;
background-position: center left; background-position: center left;
} }
#dropArea { #dropArea {
border: 2px dashed #ccc; border: 2px dashed #ccc;
border-radius: 20px; border-radius: 20px;
width: 100%; width: 100%;
font-family: sans-serif; font-family: sans-serif;
padding: 50px 0px 50px 0px; padding: 50px 0px 50px 0px;
} }
#dropArea.highlight { #dropArea.highlight {
border-color: purple; border-color: purple;
} }
.dragregion { .dragregion {
text-align: center; text-align: center;
} }
.image { .image {
width: 100%; width: 100%;
} }
div.nonmedia { div.nonmedia {
height: 100px; height: 100px;
width: 100%; width: 100%;
} }
div.nonmedia p { div.nonmedia p {
color: #444; color: #444;
font-size: 20px; font-size: 20px;
font-weight: 400; font-weight: 400;
line-height: 100px; line-height: 100px;
text-align: center; text-align: center;
} }
label { label {
text-align: center; text-align: center;
} }
.video { .video {
position: relative; position: relative;
} }
.video .overlay { .video .overlay {
position: absolute; position: absolute;
top: 0%; top: 0%;
left: 70%; left: 70%;
transform: translateY(0%) translateX(70%); transform: translateY(0%) translateX(70%);
z-index: 1; z-index: 1;
border-radius: 25px; border-radius: 25px;
border: 2px solid #73AD21; border: 2px solid #73AD21;
padding: 5px; padding: 5px;
background-color: #eee; background-color: #eee;
} }
.video .overlay a { .video .overlay a {
color: #73AD21; color: #73AD21;
font-size: 12px; font-size: 12px;
font-weight: 400; font-weight: 400;
line-height: 20px; line-height: 20px;
text-align: center; text-align: center;
} }

View file

@ -1,141 +1,141 @@
hr { hr {
margin: 20px 0; margin: 20px 0;
border: 0; border: 0;
border-top: 1px dashed #c5c5c5; border-top: 1px dashed #c5c5c5;
border-bottom: 1px dashed #f7f7f7; border-bottom: 1px dashed #f7f7f7;
} }
.learn a { .learn a {
font-weight: normal; font-weight: normal;
text-decoration: none; text-decoration: none;
color: #b83f45; color: #b83f45;
} }
.learn a:hover { .learn a:hover {
text-decoration: underline; text-decoration: underline;
color: #787e7e; color: #787e7e;
} }
.learn h3, .learn h3,
.learn h4, .learn h4,
.learn h5 { .learn h5 {
margin: 10px 0; margin: 10px 0;
font-weight: 500; font-weight: 500;
line-height: 1.2; line-height: 1.2;
color: #000; color: #000;
} }
.learn h3 { .learn h3 {
font-size: 24px; font-size: 24px;
} }
.learn h4 { .learn h4 {
font-size: 18px; font-size: 18px;
} }
.learn h5 { .learn h5 {
margin-bottom: 0; margin-bottom: 0;
font-size: 14px; font-size: 14px;
} }
.learn ul { .learn ul {
padding: 0; padding: 0;
margin: 0 0 30px 25px; margin: 0 0 30px 25px;
} }
.learn li { .learn li {
line-height: 20px; line-height: 20px;
} }
.learn p { .learn p {
font-size: 15px; font-size: 15px;
font-weight: 300; font-weight: 300;
line-height: 1.3; line-height: 1.3;
margin-top: 0; margin-top: 0;
margin-bottom: 0; margin-bottom: 0;
} }
#issue-count { #issue-count {
display: none; display: none;
} }
.quote { .quote {
border: none; border: none;
margin: 20px 0 60px 0; margin: 20px 0 60px 0;
} }
.quote p { .quote p {
font-style: italic; font-style: italic;
} }
.quote p:before { .quote p:before {
content: '“'; content: '“';
font-size: 50px; font-size: 50px;
opacity: .15; opacity: .15;
position: absolute; position: absolute;
top: -20px; top: -20px;
left: 3px; left: 3px;
} }
.quote p:after { .quote p:after {
content: '”'; content: '”';
font-size: 50px; font-size: 50px;
opacity: .15; opacity: .15;
position: absolute; position: absolute;
bottom: -42px; bottom: -42px;
right: 3px; right: 3px;
} }
.quote footer { .quote footer {
position: absolute; position: absolute;
bottom: -40px; bottom: -40px;
right: 0; right: 0;
} }
.quote footer img { .quote footer img {
border-radius: 3px; border-radius: 3px;
} }
.quote footer a { .quote footer a {
margin-left: 5px; margin-left: 5px;
vertical-align: middle; vertical-align: middle;
} }
.speech-bubble { .speech-bubble {
position: relative; position: relative;
padding: 10px; padding: 10px;
background: rgba(0, 0, 0, .04); background: rgba(0, 0, 0, .04);
border-radius: 5px; border-radius: 5px;
} }
.speech-bubble:after { .speech-bubble:after {
content: ''; content: '';
position: absolute; position: absolute;
top: 100%; top: 100%;
right: 30px; right: 30px;
border: 13px solid transparent; border: 13px solid transparent;
border-top-color: rgba(0, 0, 0, .04); border-top-color: rgba(0, 0, 0, .04);
} }
.learn-bar > .learn { .learn-bar > .learn {
position: absolute; position: absolute;
width: 272px; width: 272px;
top: 8px; top: 8px;
left: -300px; left: -300px;
padding: 10px; padding: 10px;
border-radius: 5px; border-radius: 5px;
background-color: rgba(255, 255, 255, .6); background-color: rgba(255, 255, 255, .6);
transition-property: left; transition-property: left;
transition-duration: 500ms; transition-duration: 500ms;
} }
@media (min-width: 899px) { @media (min-width: 899px) {
.learn-bar { .learn-bar {
width: auto; width: auto;
padding-left: 300px; padding-left: 300px;
} }
.learn-bar > .learn { .learn-bar > .learn {
left: 8px; left: 8px;
} }
} }

View file

@ -1,42 +1,42 @@
.todohome { .todohome {
margin: 130px 0 40px 0; margin: 130px 0 40px 0;
position: relative; position: relative;
} }
.todohome h1 { .todohome h1 {
position: absolute; position: absolute;
top: -140px; top: -140px;
width: 100%; width: 100%;
font-size: 80px; font-size: 80px;
font-weight: 200; font-weight: 200;
text-align: center; text-align: center;
color: #b83f45; color: #b83f45;
-webkit-text-rendering: optimizeLegibility; -webkit-text-rendering: optimizeLegibility;
-moz-text-rendering: optimizeLegibility; -moz-text-rendering: optimizeLegibility;
text-rendering: optimizeLegibility; text-rendering: optimizeLegibility;
} }
.todohome section { .todohome section {
padding-top: 1px; padding-top: 1px;
text-align: center; text-align: center;
} }
.todohome h2 { .todohome h2 {
padding-bottom: 48px; padding-bottom: 48px;
font-size: 28px; font-size: 28px;
font-weight: 300; font-weight: 300;
line-height: 1.5; line-height: 1.5;
} }
.todohome .button { .todohome .button {
padding: 13px 45px; padding: 13px 45px;
font-size: 16px; font-size: 16px;
font-weight: 500; font-weight: 500;
color: white; color: white;
border-radius: 5px; border-radius: 5px;
background: #d83f45; background: #d83f45;
} }
.todohome a.button { .todohome a.button {
text-decoration: none; text-decoration: none;
} }

View file

@ -1,393 +1,393 @@
html, html,
body { body {
margin: 0; margin: 0;
padding: 0; padding: 0;
} }
button { button {
margin: 0; margin: 0;
padding: 0; padding: 0;
border: 0; border: 0;
background: none; background: none;
font-size: 100%; font-size: 100%;
vertical-align: baseline; vertical-align: baseline;
font-family: inherit; font-family: inherit;
font-weight: inherit; font-weight: inherit;
color: inherit; color: inherit;
-webkit-appearance: none; -webkit-appearance: none;
appearance: none; appearance: none;
-webkit-font-smoothing: antialiased; -webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale; -moz-osx-font-smoothing: grayscale;
} }
body { body {
font: 14px 'Helvetica Neue', Helvetica, Arial, sans-serif; font: 14px 'Helvetica Neue', Helvetica, Arial, sans-serif;
line-height: 1.4em; line-height: 1.4em;
background: #111111; background: #111111;
color: #f5f5f5; color: #f5f5f5;
min-width: 230px; min-width: 230px;
max-width: 550px; max-width: 550px;
margin: 0 auto; margin: 0 auto;
-webkit-font-smoothing: antialiased; -webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale; -moz-osx-font-smoothing: grayscale;
font-weight: 300; font-weight: 300;
} }
.view .header { .view .header {
background: #121122; background: #121122;
} }
.hidden { .hidden {
display: none; display: none;
} }
.todoapp { .todoapp {
background: #121212; background: #121212;
margin: 130px 0 40px 0; margin: 130px 0 40px 0;
position: relative; position: relative;
box-shadow: 0 2px 4px 0 rgba(0, 0, 0, 0.2), box-shadow: 0 2px 4px 0 rgba(0, 0, 0, 0.2),
0 25px 50px 0 rgba(0, 0, 0, 0.1); 0 25px 50px 0 rgba(0, 0, 0, 0.1);
} }
.todoapp input::-webkit-input-placeholder { .todoapp input::-webkit-input-placeholder {
font-style: italic; font-style: italic;
font-weight: 400; font-weight: 400;
color: #f5f5f5; color: #f5f5f5;
text-align: center; text-align: center;
} }
.todoapp input::-moz-placeholder { .todoapp input::-moz-placeholder {
font-style: italic; font-style: italic;
font-weight: 400; font-weight: 400;
color: #f5f5f5; color: #f5f5f5;
text-align: center; text-align: center;
} }
.todoapp input::input-placeholder { .todoapp input::input-placeholder {
font-style: italic; font-style: italic;
font-weight: 400; font-weight: 400;
color: #f5f5f5; color: #f5f5f5;
text-align: center; text-align: center;
} }
.todoapp h1 { .todoapp h1 {
position: absolute; position: absolute;
top: -140px; top: -140px;
width: 100%; width: 100%;
font-size: 80px; font-size: 80px;
font-weight: 200; font-weight: 200;
text-align: center; text-align: center;
color: #b83f45; color: #b83f45;
-webkit-text-rendering: optimizeLegibility; -webkit-text-rendering: optimizeLegibility;
-moz-text-rendering: optimizeLegibility; -moz-text-rendering: optimizeLegibility;
text-rendering: optimizeLegibility; text-rendering: optimizeLegibility;
} }
.new-todo, .new-todo,
.edit { .edit {
position: relative; position: relative;
margin: 0; margin: 0;
width: 100%; width: 100%;
font-size: 24px; font-size: 24px;
font-family: inherit; font-family: inherit;
font-weight: inherit; font-weight: inherit;
line-height: 1.4em; line-height: 1.4em;
color: inherit; color: inherit;
padding: 6px; padding: 6px;
-webkit-font-smoothing: antialiased; -webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale; -moz-osx-font-smoothing: grayscale;
} }
.new-todo { .new-todo {
padding: 16px 16px 16px 60px; padding: 16px 16px 16px 60px;
height: 65px; height: 65px;
border: none; border: none;
background: rgba(0, 0, 0, 0.003); background: rgba(0, 0, 0, 0.003);
box-shadow: inset 0 -2px 1px rgba(0,0,0,0.03); box-shadow: inset 0 -2px 1px rgba(0,0,0,0.03);
} }
.main { .main {
position: relative; position: relative;
z-index: 2; z-index: 2;
} }
.toggle-all { .toggle-all {
width: 1px; width: 1px;
height: 1px; height: 1px;
border: none; /* Mobile Safari */ border: none; /* Mobile Safari */
opacity: 0; opacity: 0;
position: absolute; position: absolute;
right: 100%; right: 100%;
bottom: 100%; bottom: 100%;
} }
.toggle-all + label { .toggle-all + label {
display: flex; display: flex;
align-items: center; align-items: center;
justify-content: center; justify-content: center;
width: 45px; width: 45px;
height: 65px; height: 65px;
font-size: 0; font-size: 0;
position: absolute; position: absolute;
top: -65px; top: -65px;
left: -0; left: -0;
} }
.toggle-all + label:before { .toggle-all + label:before {
content: ''; content: '';
display: inline-block; display: inline-block;
font-size: 22px; font-size: 22px;
color: #949494; color: #949494;
padding: 10px 27px 10px 27px; padding: 10px 27px 10px 27px;
-webkit-transform: rotate(90deg); -webkit-transform: rotate(90deg);
transform: rotate(90deg); transform: rotate(90deg);
} }
.toggle-all:checked + label:before { .toggle-all:checked + label:before {
color: #484848; color: #484848;
} }
.todo-list { .todo-list {
margin: 0; margin: 0;
padding: 0; padding: 0;
list-style: none; list-style: none;
} }
.todo-list li { .todo-list li {
position: relative; position: relative;
font-size: 24px; font-size: 24px;
} }
.todo-list li:last-child { .todo-list li:last-child {
border-bottom: none; border-bottom: none;
} }
.todo-list li.editing { .todo-list li.editing {
border-bottom: none; border-bottom: none;
padding: 0; padding: 0;
} }
.todo-list li.editing .edit { .todo-list li.editing .edit {
display: block; display: block;
width: calc(100% - 43px); width: calc(100% - 43px);
padding: 12px 16px; padding: 12px 16px;
margin: 0 0 0 43px; margin: 0 0 0 43px;
} }
.todo-list li.editing .view { .todo-list li.editing .view {
display: none; display: none;
} }
.todo-list li .toggle { .todo-list li .toggle {
text-align: center; text-align: center;
width: 40px; width: 40px;
/* auto, since non-WebKit browsers doesn't support input styling */ /* auto, since non-WebKit browsers doesn't support input styling */
height: auto; height: auto;
position: absolute; position: absolute;
top: 0; top: 0;
bottom: 0; bottom: 0;
margin: auto 0; margin: auto 0;
border: none; /* Mobile Safari */ border: none; /* Mobile Safari */
-webkit-appearance: none; -webkit-appearance: none;
appearance: none; appearance: none;
} }
.todo-list li .toggle { .todo-list li .toggle {
opacity: 0; opacity: 0;
} }
.todo-list li .toggle + label { .todo-list li .toggle + label {
/* /*
Firefox requires `#` to be escaped - https://bugzilla.mozilla.org/show_bug.cgi?id=922433 Firefox requires `#` to be escaped - https://bugzilla.mozilla.org/show_bug.cgi?id=922433
IE and Edge requires *everything* to be escaped to render, so we do that instead of just the `#` - https://developer.microsoft.com/en-us/microsoft-edge/platform/issues/7157459/ IE and Edge requires *everything* to be escaped to render, so we do that instead of just the `#` - https://developer.microsoft.com/en-us/microsoft-edge/platform/issues/7157459/
*/ */
background-image: url('data:image/svg+xml;utf8,%3Csvg%20xmlns%3D%22http%3A//www.w3.org/2000/svg%22%20width%3D%2240%22%20height%3D%2240%22%20viewBox%3D%22-10%20-18%20100%20135%22%3E%3Ccircle%20cx%3D%2250%22%20cy%3D%2250%22%20r%3D%2250%22%20fill%3D%22none%22%20stroke%3D%22%23949494%22%20stroke-width%3D%223%22/%3E%3C/svg%3E'); background-image: url('data:image/svg+xml;utf8,%3Csvg%20xmlns%3D%22http%3A//www.w3.org/2000/svg%22%20width%3D%2240%22%20height%3D%2240%22%20viewBox%3D%22-10%20-18%20100%20135%22%3E%3Ccircle%20cx%3D%2250%22%20cy%3D%2250%22%20r%3D%2250%22%20fill%3D%22none%22%20stroke%3D%22%23949494%22%20stroke-width%3D%223%22/%3E%3C/svg%3E');
background-repeat: no-repeat; background-repeat: no-repeat;
background-position: center left; background-position: center left;
} }
.todo-list li .toggle:checked + label { .todo-list li .toggle:checked + label {
background-image: url('data:image/svg+xml;utf8,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20width%3D%2240%22%20height%3D%2240%22%20viewBox%3D%22-10%20-18%20100%20135%22%3E%3Ccircle%20cx%3D%2250%22%20cy%3D%2250%22%20r%3D%2250%22%20fill%3D%22none%22%20stroke%3D%22%2359A193%22%20stroke-width%3D%223%22%2F%3E%3Cpath%20fill%3D%22%233EA390%22%20d%3D%22M72%2025L42%2071%2027%2056l-4%204%2020%2020%2034-52z%22%2F%3E%3C%2Fsvg%3E'); background-image: url('data:image/svg+xml;utf8,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20width%3D%2240%22%20height%3D%2240%22%20viewBox%3D%22-10%20-18%20100%20135%22%3E%3Ccircle%20cx%3D%2250%22%20cy%3D%2250%22%20r%3D%2250%22%20fill%3D%22none%22%20stroke%3D%22%2359A193%22%20stroke-width%3D%223%22%2F%3E%3Cpath%20fill%3D%22%233EA390%22%20d%3D%22M72%2025L42%2071%2027%2056l-4%204%2020%2020%2034-52z%22%2F%3E%3C%2Fsvg%3E');
} }
.todo-list li label { .todo-list li label {
word-break: break-all; word-break: break-all;
padding: 15px 15px 15px 60px; padding: 15px 15px 15px 60px;
display: block; display: block;
line-height: 1.2; line-height: 1.2;
transition: color 0.4s; transition: color 0.4s;
font-weight: 400; font-weight: 400;
color: #BB86FC; color: #BB86FC;
} }
.todo-list li.completed label { .todo-list li.completed label {
color: #949494; color: #949494;
text-decoration: line-through; text-decoration: line-through;
} }
.todo-list li .destroy { .todo-list li .destroy {
display: none; display: none;
position: absolute; position: absolute;
top: 0; top: 0;
right: 10px; right: 10px;
bottom: 0; bottom: 0;
width: 40px; width: 40px;
height: 40px; height: 40px;
margin: auto 0; margin: auto 0;
font-size: 30px; font-size: 30px;
color: #949494; color: #949494;
transition: color 0.2s ease-out; transition: color 0.2s ease-out;
} }
.todo-list li .destroy:hover, .todo-list li .destroy:hover,
.todo-list li .destroy:focus { .todo-list li .destroy:focus {
color: #C18585; color: #C18585;
} }
.todo-list li .destroy:after { .todo-list li .destroy:after {
content: '×'; content: '×';
display: block; display: block;
height: 100%; height: 100%;
line-height: 1.1; line-height: 1.1;
} }
.todo-list li:hover .destroy { .todo-list li:hover .destroy {
display: block; display: block;
} }
.todo-list li .edit { .todo-list li .edit {
display: none; display: none;
} }
.todo-list li.editing:last-child { .todo-list li.editing:last-child {
margin-bottom: -1px; margin-bottom: -1px;
} }
.footer { .footer {
padding: 10px 15px; padding: 10px 15px;
height: 20px; height: 20px;
text-align: center; text-align: center;
font-size: 15px; font-size: 15px;
border-top: 1px solid #e6e6e6; border-top: 1px solid #e6e6e6;
} }
.footer:before { .footer:before {
content: ''; content: '';
position: absolute; position: absolute;
right: 0; right: 0;
bottom: 0; bottom: 0;
left: 0; left: 0;
height: 50px; height: 50px;
overflow: hidden; overflow: hidden;
box-shadow: 0 1px 1px rgba(0, 0, 0, 0.2), box-shadow: 0 1px 1px rgba(0, 0, 0, 0.2),
0 8px 0 -3px #f6f6f6, 0 8px 0 -3px #f6f6f6,
0 9px 1px -3px rgba(0, 0, 0, 0.2), 0 9px 1px -3px rgba(0, 0, 0, 0.2),
0 16px 0 -6px #f6f6f6, 0 16px 0 -6px #f6f6f6,
0 17px 2px -6px rgba(0, 0, 0, 0.2); 0 17px 2px -6px rgba(0, 0, 0, 0.2);
} }
.todo-count { .todo-count {
float: left; float: left;
text-align: left; text-align: left;
} }
.todo-count strong { .todo-count strong {
font-weight: 300; font-weight: 300;
} }
.filters { .filters {
margin: 0; margin: 0;
padding: 0; padding: 0;
list-style: none; list-style: none;
position: absolute; position: absolute;
right: 0; right: 0;
left: 0; left: 0;
} }
.filters li { .filters li {
display: inline; display: inline;
} }
.filters li a { .filters li a {
color: inherit; color: inherit;
margin: 3px; margin: 3px;
padding: 3px 7px; padding: 3px 7px;
text-decoration: none; text-decoration: none;
border: 1px solid transparent; border: 1px solid transparent;
border-radius: 3px; border-radius: 3px;
} }
.filters li a:hover { .filters li a:hover {
border-color: #DB7676; border-color: #DB7676;
} }
.filters li a.selected { .filters li a.selected {
border-color: #CE4646; border-color: #CE4646;
} }
.clear-completed, .clear-completed,
html .clear-completed:active { html .clear-completed:active {
float: right; float: right;
position: relative; position: relative;
line-height: 19px; line-height: 19px;
text-decoration: none; text-decoration: none;
cursor: pointer; cursor: pointer;
} }
.clear-completed:hover { .clear-completed:hover {
text-decoration: underline; text-decoration: underline;
} }
.info { .info {
margin: 65px auto 0; margin: 65px auto 0;
color: #4d4d4d; color: #4d4d4d;
font-size: 11px; font-size: 11px;
text-shadow: 0 1px 0 rgba(255, 255, 255, 0.5); text-shadow: 0 1px 0 rgba(255, 255, 255, 0.5);
text-align: center; text-align: center;
} }
.info p { .info p {
line-height: 1; line-height: 1;
} }
.info a { .info a {
color: inherit; color: inherit;
text-decoration: none; text-decoration: none;
font-weight: 400; font-weight: 400;
} }
.info a:hover { .info a:hover {
text-decoration: underline; text-decoration: underline;
} }
/* /*
Hack to remove background from Mobile Safari. Hack to remove background from Mobile Safari.
Can't use it globally since it destroys checkboxes in Firefox Can't use it globally since it destroys checkboxes in Firefox
*/ */
@media screen and (-webkit-min-device-pixel-ratio:0) { @media screen and (-webkit-min-device-pixel-ratio:0) {
.toggle-all, .toggle-all,
.todo-list li .toggle { .todo-list li .toggle {
background: none; background: none;
} }
.todo-list li .toggle { .todo-list li .toggle {
height: 40px; height: 40px;
} }
} }
@media (max-width: 430px) { @media (max-width: 430px) {
.footer { .footer {
height: 50px; height: 50px;
} }
.filters { .filters {
bottom: 10px; bottom: 10px;
} }
} }
:focus, :focus,
.toggle:focus + label, .toggle:focus + label,
.toggle-all:focus + label { .toggle-all:focus + label {
box-shadow: 0 0 2px 2px #CF7D7D; box-shadow: 0 0 2px 2px #CF7D7D;
outline: 0; outline: 0;
} }

View file

@ -1,116 +1,116 @@
.prompt { .prompt {
max-width: 400px; max-width: 400px;
margin: 50px auto; margin: 50px auto;
padding: 25px; padding: 25px;
background: #11111; background: #11111;
border: 1px solid #e6e6e6; border: 1px solid #e6e6e6;
border-radius: 8px; border-radius: 8px;
} }
button { button {
display: block; display: block;
padding: 10px; padding: 10px;
width: 100%; width: 100%;
border-radius: 3px; border-radius: 3px;
background: #d83f45; background: #d83f45;
font-size: 14px; font-size: 14px;
font-weight: 700; font-weight: 700;
color: white; color: white;
cursor: pointer; cursor: pointer;
} }
a.button { a.button {
box-sizing: border-box; box-sizing: border-box;
display: block; display: block;
padding: 10px; padding: 10px;
width: 100%; width: 100%;
border-radius: 3px; border-radius: 3px;
background: #000; background: #000;
font-size: 14px; font-size: 14px;
font-weight: 700; font-weight: 700;
text-align: center; text-align: center;
text-decoration: none; text-decoration: none;
color: white; color: white;
} }
a.google { a.google {
background: #4787ed; background: #4787ed;
} }
a.facebook { a.facebook {
background: #4267b2; background: #4267b2;
} }
button:hover { button:hover {
background-color: #c83f45; background-color: #c83f45;
} }
h1 { h1 {
margin: 0 0 20px 0; margin: 0 0 20px 0;
padding: 0 0 5px 0; padding: 0 0 5px 0;
font-size: 24px; font-size: 24px;
font-weight: 500; font-weight: 500;
} }
h3 { h3 {
margin-top: 0; margin-top: 0;
font-size: 24px; font-size: 24px;
font-weight: 300; font-weight: 300;
text-align: center; text-align: center;
color: #b83f45; color: #b83f45;
} }
form section { form section {
margin: 0 0 20px 0; margin: 0 0 20px 0;
position: relative; /* for password toggle positioning */ position: relative; /* for password toggle positioning */
} }
label { label {
display: block; display: block;
margin: 0 0 3px 0; margin: 0 0 3px 0;
font-size: 14px; font-size: 14px;
font-weight: 500; font-weight: 500;
} }
input { input {
box-sizing: border-box; box-sizing: border-box;
width: 100%; width: 100%;
padding: 10px; padding: 10px;
font-size: 14px; font-size: 14px;
border: 1px solid #d9d9d9; border: 1px solid #d9d9d9;
border-radius: 5px; border-radius: 5px;
background-color:#200; background-color:#200;
color:#fff; color:#fff;
} }
input[type=email]:not(:focus):invalid, input[type=email]:not(:focus):invalid,
input[type=password]:not(:focus):invalid { input[type=password]:not(:focus):invalid {
color: red; color: red;
outline-color: red; outline-color: red;
} }
hr { hr {
border-top: 1px solid #d9d9d9; border-top: 1px solid #d9d9d9;
border-bottom: none; border-bottom: none;
} }
p.instructions { p.instructions {
font-weight: 400; font-weight: 400;
} }
p.help { p.help {
text-align: center; text-align: center;
font-weight: 400; font-weight: 400;
} }
/* background image by Cole Bemis <https://feathericons.com> */ /* background image by Cole Bemis <https://feathericons.com> */
.messages p { .messages p {
font-size: 14px; font-size: 14px;
font-weight: 400; font-weight: 400;
line-height: 1.3; line-height: 1.3;
color: #d83f45; color: #d83f45;
padding-left: 20px; padding-left: 20px;
background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='16' height='16' viewBox='0 0 24 24' fill='none' stroke='%23d83f45' stroke-width='2' stroke-linecap='round' stroke-linejoin='round' class='feather feather-alert-circle'%3E%3Ccircle cx='12' cy='12' r='10'%3E%3C/circle%3E%3Cline x1='12' y1='8' x2='12' y2='12'%3E%3C/line%3E%3Cline x1='12' y1='16' x2='12.01' y2='16'%3E%3C/line%3E%3C/svg%3E"); background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='16' height='16' viewBox='0 0 24 24' fill='none' stroke='%23d83f45' stroke-width='2' stroke-linecap='round' stroke-linejoin='round' class='feather feather-alert-circle'%3E%3Ccircle cx='12' cy='12' r='10'%3E%3C/circle%3E%3Cline x1='12' y1='8' x2='12' y2='12'%3E%3C/line%3E%3Cline x1='12' y1='16' x2='12.01' y2='16'%3E%3C/line%3E%3C/svg%3E");
background-repeat: no-repeat; background-repeat: no-repeat;
background-position: center left; background-position: center left;
} }

View file

Before

Width:  |  Height:  |  Size: 954 B

After

Width:  |  Height:  |  Size: 954 B

Before After
Before After

View file

Before

Width:  |  Height:  |  Size: 3 KiB

After

Width:  |  Height:  |  Size: 3 KiB

Before After
Before After

View file

Before

Width:  |  Height:  |  Size: 15 KiB

After

Width:  |  Height:  |  Size: 15 KiB

Before After
Before After

View file

@ -1,143 +1,143 @@
/* eslint-env browser: true */ /* eslint-env browser: true */
function copyURI(evt) { function copyURI(evt) {
evt.preventDefault(); evt.preventDefault();
navigator.clipboard.writeText(absolutePath(evt.target.getAttribute("src"))).then(() => { navigator.clipboard.writeText(absolutePath(evt.target.getAttribute("src"))).then(() => {
/* clipboard successfully set */ /* clipboard successfully set */
console.log("copied"); console.log("copied");
}, () => { }, () => {
/* clipboard write failed */ /* clipboard write failed */
console.log("failed"); console.log("failed");
}); });
} }
function copyA(evt) { function copyA(evt) {
evt.preventDefault(); evt.preventDefault();
navigator.clipboard.writeText(absolutePath(evt.target.getAttribute("href"))).then(() => { navigator.clipboard.writeText(absolutePath(evt.target.getAttribute("href"))).then(() => {
console.log("copied"); console.log("copied");
}, () => { }, () => {
console.log("failed"); console.log("failed");
}); });
} }
function copyPath(evt) { function copyPath(evt) {
navigator.clipboard.writeText(absolutePath(evt)).then(() => { navigator.clipboard.writeText(absolutePath(evt)).then(() => {
console.log("copied"); console.log("copied");
}, () => { }, () => {
console.log("failed"); console.log("failed");
}); });
} }
function absolutePath (href) { function absolutePath (href) {
let link = document.createElement("a"); let link = document.createElement("a");
link.href = href; link.href = href;
return link.href; return link.href;
} }
function extension(string) { function extension(string) {
return string.slice((string.lastIndexOf(".") - 2 >>> 0) + 2); return string.slice((string.lastIndexOf(".") - 2 >>> 0) + 2);
} }
let dropArea = document.getElementById("dropArea"); let dropArea = document.getElementById("dropArea");
["dragenter", "dragover", "dragleave", "drop"].forEach(eventName => { ["dragenter", "dragover", "dragleave", "drop"].forEach(eventName => {
dropArea.addEventListener(eventName, preventDefaults, false); dropArea.addEventListener(eventName, preventDefaults, false);
}); });
function preventDefaults (e) { function preventDefaults (e) {
e.preventDefault(); e.preventDefault();
e.stopPropagation(); e.stopPropagation();
} }
["dragenter", "dragover"].forEach(eventName => { ["dragenter", "dragover"].forEach(eventName => {
dropArea.addEventListener(eventName, highlight, false); dropArea.addEventListener(eventName, highlight, false);
}) })
;["dragleave", "drop"].forEach(eventName => { ;["dragleave", "drop"].forEach(eventName => {
dropArea.addEventListener(eventName, unhighlight, false); dropArea.addEventListener(eventName, unhighlight, false);
}); });
function highlight(e) { function highlight(e) {
dropArea.classList.add("highlight"); dropArea.classList.add("highlight");
} }
function unhighlight(e) { function unhighlight(e) {
dropArea.classList.remove("highlight"); dropArea.classList.remove("highlight");
} }
dropArea.addEventListener("drop", handleDrop, false); dropArea.addEventListener("drop", handleDrop, false);
window.addEventListener("paste", handlePaste); window.addEventListener("paste", handlePaste);
function handleDrop(e) { function handleDrop(e) {
let dt = e.dataTransfer; let dt = e.dataTransfer;
let files = dt.files; let files = dt.files;
handleFiles(files); handleFiles(files);
} }
function handlePaste(e) { function handlePaste(e) {
// Get the data of clipboard // Get the data of clipboard
const clipboardItems = e.clipboardData.items; const clipboardItems = e.clipboardData.items;
const items = [].slice.call(clipboardItems).filter(function (item) { const items = [].slice.call(clipboardItems).filter(function (item) {
// Filter the image items only // Filter the image items only
return item.type.indexOf("image") !== -1; return item.type.indexOf("image") !== -1;
}); });
if (items.length === 0) { if (items.length === 0) {
return; return;
} }
const item = items[0]; const item = items[0];
// Get the blob of image // Get the blob of image
const blob = item.getAsFile(); const blob = item.getAsFile();
console.log(blob); console.log(blob);
uploadFile(blob); uploadFile(blob);
previewFile(blob); previewFile(blob);
} }
function handleFiles(files) { function handleFiles(files) {
files = [...files]; files = [...files];
files.forEach(uploadFile); files.forEach(uploadFile);
files.forEach(previewFile); files.forEach(previewFile);
} }
function previewFile(file) { function previewFile(file) {
let reader = new FileReader(); let reader = new FileReader();
reader.readAsDataURL(file); reader.readAsDataURL(file);
reader.onloadend = function() { reader.onloadend = function() {
let img = document.createElement("img"); let img = document.createElement("img");
img.src = reader.result; img.src = reader.result;
img.className = "image"; img.className = "image";
document.getElementById("gallery").appendChild(img); document.getElementById("gallery").appendChild(img);
console.log(document.getElementById("fileupload")); console.log(document.getElementById("fileupload"));
document.getElementById("fileupload").src = img.src; document.getElementById("fileupload").src = img.src;
}; };
} }
function uploadFile(file) { function uploadFile(file) {
let xhr = new XMLHttpRequest(); let xhr = new XMLHttpRequest();
let formData = new FormData(); let formData = new FormData();
let reader = new FileReader(); let reader = new FileReader();
xhr.open("POST", "/", true); xhr.open("POST", "/", true);
xhr.addEventListener("readystatechange", function(e) { xhr.addEventListener("readystatechange", function(e) {
if (xhr.readyState == 4 && xhr.status == 200) { if (xhr.readyState == 4 && xhr.status == 200) {
location.reload(); location.reload();
} }
else if (xhr.readyState == 4 && xhr.status != 200) { else if (xhr.readyState == 4 && xhr.status != 200) {
// Error. Inform the user // Error. Inform the user
} }
}); });
if (file == null || file == undefined) { if (file == null || file == undefined) {
//file = reader.readAsDataURL(document.getElementById("fileupload").files[0]); //file = reader.readAsDataURL(document.getElementById("fileupload").files[0]);
//file = reader.readAsDataURL(document.querySelector("#fileupload").files[0]); //file = reader.readAsDataURL(document.querySelector("#fileupload").files[0]);
file = document.querySelector("#fileupload").files[0]; file = document.querySelector("#fileupload").files[0];
} }
formData.append("fileupload", file); formData.append("fileupload", file);
formData.append("expire", document.getElementById("expire").value); formData.append("expire", document.getElementById("expire").value);
console.log(formData); console.log(formData);
xhr.send(formData); xhr.send(formData);
} }

View file

@ -3,7 +3,7 @@ const express = require("express");
const passport = require("passport"); const passport = require("passport");
const LocalStrategy = require("passport-local"); const LocalStrategy = require("passport-local");
let db = require("../db"); let db = require("../db").db;
let router = express.Router(); let router = express.Router();

View file

@ -10,7 +10,7 @@ ffmpeg.setFfprobePath(ffprobepath);
const fs = require("fs"); const fs = require("fs");
let db = require("../db"); let db = require("../db").db;
let {checkAuth, convert, handleUpload} = require("./middleware"); let {checkAuth, convert, handleUpload} = require("./middleware");
function extension(str){ function extension(str){

View file

@ -7,7 +7,7 @@ ffmpeg.setFfprobePath(ffprobepath);
const fs = require("fs"); const fs = require("fs");
const process = require("process"); const process = require("process");
let db = require("../db.js"); let db = require("../db.js").db;
function extension(str){ function extension(str){
let file = str.split("/").pop(); let file = str.split("/").pop();

View file

@ -1 +1 @@
<h1><%= error %></h1> <h1><%= error %></h1>

View file

@ -1,56 +1,56 @@
<% <%
function extension(str){ function extension(str){
let file = str.split('/').pop(); let file = str.split('/').pop();
return [file.substr(0,file.lastIndexOf('.')),file.substr(file.lastIndexOf('.'),file.length).toLowerCase()] return [file.substr(0,file.lastIndexOf('.')),file.substr(file.lastIndexOf('.'),file.length).toLowerCase()]
} }
%> %>
<!DOCTYPE html> <!DOCTYPE html>
<html> <html>
<head> <head>
<% if (extension(url)[1] == ".gif") { %> <% if (extension(url)[1] == ".gif") { %>
<meta name="twitter:card" content="summary_large_image"> <meta name="twitter:card" content="summary_large_image">
<link rel="alternate" type="application/json+oembed" href="<%= host %>/uploads/oembed-<%= extension(url)[0]+extension(url)[1] %>.json"></link> <link rel="alternate" type="application/json+oembed" href="<%= host %>/uploads/oembed-<%= extension(url)[0]+extension(url)[1] %>.json"></link>
<meta property="og:title" content="<%= extension(url)[0] %>.gif"></meta> <meta property="og:title" content="<%= extension(url)[0] %>.gif"></meta>
<meta property="og:description" content="Click to view the GIF"></meta> <meta property="og:description" content="Click to view the GIF"></meta>
<meta property="og:site_name" content="embedder"></meta> <meta property="og:site_name" content="embedder"></meta>
<meta property="og:type" content="article"></meta> <meta property="og:type" content="article"></meta>
<meta property="og:image" content="<%= host %>/uploads/<%= extension(url)[0] %>.gif"></meta> <meta property="og:image" content="<%= host %>/uploads/<%= extension(url)[0] %>.gif"></meta>
<meta property="og:image:width" content="<%= width %>"></meta> <meta property="og:image:width" content="<%= width %>"></meta>
<meta property="og:image:height" content="<%= height %>"></meta> <meta property="og:image:height" content="<%= height %>"></meta>
<meta property="og:image:type" content="image/gif"></meta> <meta property="og:image:type" content="image/gif"></meta>
<meta property="og:url" content="<%= host %>/uploads/<%= extension(url)[0] %>.gif"></meta> <meta property="og:url" content="<%= host %>/uploads/<%= extension(url)[0] %>.gif"></meta>
<% } else if (extension(url)[1] == ".mp4") { %> <% } else if (extension(url)[1] == ".mp4") { %>
<meta name="twitter:card" content="player"> <meta name="twitter:card" content="player">
<link rel="alternate" type="application/json+oembed" href="<%= host %>/uploads/oembed-<%= extension(url)[0]+extension(url)[1] %>.json"></link> <link rel="alternate" type="application/json+oembed" href="<%= host %>/uploads/oembed-<%= extension(url)[0]+extension(url)[1] %>.json"></link>
<meta property="og:title" content="<%= extension(url)[0] %>.mp4"></meta> <meta property="og:title" content="<%= extension(url)[0] %>.mp4"></meta>
<meta property="og:description" content="Click to view the GIFv"></meta> <meta property="og:description" content="Click to view the GIFv"></meta>
<meta property="og:site_name" content="embedder"></meta> <meta property="og:site_name" content="embedder"></meta>
<meta property="og:type" content="article"></meta> <meta property="og:type" content="article"></meta>
<meta property="og:video" content="<%= host %>/uploads/<%= extension(url)[0] %>.mp4"></meta> <meta property="og:video" content="<%= host %>/uploads/<%= extension(url)[0] %>.mp4"></meta>
<meta property="og:video:width" content="<%= width %>"></meta> <meta property="og:video:width" content="<%= width %>"></meta>
<meta property="og:video:height" content="<%= height %>"></meta> <meta property="og:video:height" content="<%= height %>"></meta>
<meta property="og:video:type" content="video/mp4"></meta> <meta property="og:video:type" content="video/mp4"></meta>
<meta property="og:url" content="<%= host %>/uploads/<%= extension(url)[0] %>.mp4"></meta> <meta property="og:url" content="<%= host %>/uploads/<%= extension(url)[0] %>.mp4"></meta>
<% } else { %> <% } else { %>
<meta name="twitter:card" content="summary_large_image"> <meta name="twitter:card" content="summary_large_image">
<link rel="alternate" type="application/json+oembed" href="<%= host %>/uploads/oembed-<%= extension(url)[0]+extension(url)[1] %>.json"></link> <link rel="alternate" type="application/json+oembed" href="<%= host %>/uploads/oembed-<%= extension(url)[0]+extension(url)[1] %>.json"></link>
<meta property="og:title" content="<%= extension(url)[0] + extension(url)[1] %>"></meta> <meta property="og:title" content="<%= extension(url)[0] + extension(url)[1] %>"></meta>
<meta property="og:description" content="Click to view the image"></meta> <meta property="og:description" content="Click to view the image"></meta>
<meta property="og:site_name" content="embedder"></meta> <meta property="og:site_name" content="embedder"></meta>
<meta property="og:type" content="article"></meta> <meta property="og:type" content="article"></meta>
<meta property="og:image" content="<%= host %>/uploads/<%= extension(url)[0] + extension(url)[1] %>"></meta> <meta property="og:image" content="<%= host %>/uploads/<%= extension(url)[0] + extension(url)[1] %>"></meta>
<meta property="og:image:width" content="<%= width %>"></meta> <meta property="og:image:width" content="<%= width %>"></meta>
<meta property="og:image:height" content="<%= height %>"></meta> <meta property="og:image:height" content="<%= height %>"></meta>
<meta property="og:image:type" content="image/<%= extension(url)[1].split('.').join("") %>"></meta> <meta property="og:image:type" content="image/<%= extension(url)[1].split('.').join("") %>"></meta>
<meta property="og:url" content="<%= host %>/uploads/<%= extension(url)[0] + extension(url)[1] %>"></meta> <meta property="og:url" content="<%= host %>/uploads/<%= extension(url)[0] + extension(url)[1] %>"></meta>
<% } %> <% } %>
</head> </head>
<body> <body>
<% if (extension(url)[1] == ".mp4") { %> <% if (extension(url)[1] == ".mp4") { %>
<video autoplay loop muted playsinline class="image" width="100%"><source src="/uploads/<%= extension(url)[0] %>.mp4"></video> <video autoplay loop muted playsinline class="image" width="100%"><source src="/uploads/<%= extension(url)[0] %>.mp4"></video>
<% } else { %> <% } else { %>
<img src="/uploads/<%= extension(url)[0] + extension(url)[1] %>" class="image" width="100%"> <img src="/uploads/<%= extension(url)[0] + extension(url)[1] %>" class="image" width="100%">
<% } %> <% } %>
</body> </body>
</html> </html>

View file

@ -1,30 +1,30 @@
<!doctype html> <!doctype html>
<html lang="en"> <html lang="en">
<head> <head>
<meta charset="utf-8"> <meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1"> <meta name="viewport" content="width=device-width, initial-scale=1">
<title>Embedder</title> <title>Embedder</title>
<link rel="stylesheet" href="/css/base.css"> <link rel="stylesheet" href="/css/base.css">
<link rel="stylesheet" href="/css/index.css"> <link rel="stylesheet" href="/css/index.css">
<link rel="stylesheet" href="/css/home.css"> <link rel="stylesheet" href="/css/home.css">
<link rel="apple-touch-icon" sizes="180x180" href="/apple-touch-icon.png"> <link rel="apple-touch-icon" sizes="180x180" href="/apple-touch-icon.png">
<link rel="icon" type="image/png" sizes="32x32" href="/favicon-32x32.png"> <link rel="icon" type="image/png" sizes="32x32" href="/favicon-32x32.png">
<link rel="icon" type="image/png" sizes="16x16" href="/favicon-16x16.png"> <link rel="icon" type="image/png" sizes="16x16" href="/favicon-16x16.png">
<link rel="manifest" href="/site.webmanifest"> <link rel="manifest" href="/site.webmanifest">
</head> </head>
<body> <body>
<section class="todohome"> <section class="todohome">
<header> <header>
<h1>Embedder</h1> <h1>Embedder</h1>
</header> </header>
<section> <section>
<h2>A media host specialized in good looking embeds for services like Discord</h2> <h2>A media host specialized in good looking embeds for services like Discord</h2>
<a class="button" href="/login">Sign in</a> <a class="button" href="/login">Sign in</a>
</section> </section>
</section> </section>
<footer class="info"> <footer class="info">
<p><a href="https://l.nekomimi.pet/project">Created by Wavering Ana</a></p> <p><a href="https://l.nekomimi.pet/project">Created by Wavering Ana</a></p>
<p><a href="https://github.com/WaveringAna/Embedder">Github</a></p> <p><a href="https://github.com/WaveringAna/Embedder">Github</a></p>
</footer> </footer>
</body> </body>
</html> </html>

View file

@ -1,104 +1,104 @@
<!doctype html> <!doctype html>
<html lang="en"> <html lang="en">
<head> <head>
<meta charset="utf-8"> <meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1"> <meta name="viewport" content="width=device-width, initial-scale=1">
<title>Embedder</title> <title>Embedder</title>
<link rel="stylesheet" href="/css/base.css"> <link rel="stylesheet" href="/css/base.css">
<link rel="stylesheet" href="/css/index.css"> <link rel="stylesheet" href="/css/index.css">
<link rel="stylesheet" href="/css/app.css"> <link rel="stylesheet" href="/css/app.css">
<link rel="apple-touch-icon" sizes="180x180" href="/apple-touch-icon.png"> <link rel="apple-touch-icon" sizes="180x180" href="/apple-touch-icon.png">
<link rel="icon" type="image/png" sizes="32x32" href="/favicon-32x32.png"> <link rel="icon" type="image/png" sizes="32x32" href="/favicon-32x32.png">
<link rel="icon" type="image/png" sizes="16x16" href="/favicon-16x16.png"> <link rel="icon" type="image/png" sizes="16x16" href="/favicon-16x16.png">
<link rel="manifest" href="/site.webmanifest"> <link rel="manifest" href="/site.webmanifest">
<% <%
function extension(string) { function extension(string) {
return string.slice((string.lastIndexOf(".") - 2 >>> 0) + 2); return string.slice((string.lastIndexOf(".") - 2 >>> 0) + 2);
} }
%> %>
</head> </head>
<body> <body>
<section class="todoapp"> <section class="todoapp">
<nav class="nav"> <nav class="nav">
<ul> <ul>
<li class="user"><%= user.name || user.username %></li> <li class="user"><%= user.name || user.username %></li>
<li> <li>
<form action="/logout" method="post"> <form action="/logout" method="post">
<button class="logout" type="submit">Sign out</button> <button class="logout" type="submit">Sign out</button>
</form> </form>
</li> </li>
</ul> </ul>
</nav> </nav>
<header class="header"> <header class="header">
<h1>Embedder</h1> <h1>Embedder</h1>
<form action="/" method="post" encType="multipart/form-data"> <form action="/" method="post" encType="multipart/form-data">
<div id="dropArea"> <div id="dropArea">
<p class="dragregion">Upload a file, copy paste, or drag n' drop into the dashed region</p> <p class="dragregion">Upload a file, copy paste, or drag n' drop into the dashed region</p>
<div id="gallery"></div> <div id="gallery"></div>
<p class="dragregion"><input class="" type="file" id="fileupload" name="fileupload"><input type="button" value="Upload" id="submit" onclick="uploadFile()"></p> <p class="dragregion"><input class="" type="file" id="fileupload" name="fileupload"><input type="button" value="Upload" id="submit" onclick="uploadFile()"></p>
<br> <br>
<br> <br>
<p class="dragregion">Select file expiration date: <select name="expire" id="expire"> <p class="dragregion">Select file expiration date: <select name="expire" id="expire">
<option value="0.00069">1 minute</option> <option value="0.00069">1 minute</option>
<option value="0.00347">5 minutes</option> <option value="0.00347">5 minutes</option>
<option value="0.0417">1 hour</option> <option value="0.0417">1 hour</option>
<option value="0.25">6 hours</option> <option value="0.25">6 hours</option>
<option value="1">1 day</option> <option value="1">1 day</option>
<option value="7">7 days</option> <option value="7">7 days</option>
<option value="14">14 days</option> <option value="14">14 days</option>
<option value="30">30 days</option> <option value="30">30 days</option>
<option selected value="">never</option> <option selected value="">never</option>
</select></p> </select></p>
<p class="dragregion">Click the file to copy the url</p> <p class="dragregion">Click the file to copy the url</p>
</div> </div>
</form> </form>
</header> </header>
<% if (Count > 0) { %> <% if (Count > 0) { %>
<section class="main"> <section class="main">
<ul class="todo-list"> <ul class="todo-list">
<% files.forEach(function(file) { %> <% files.forEach(function(file) { %>
<li> <li>
<form action="<%= file.url %>" method="post"> <form action="<%= file.url %>" method="post">
<div class="view"> <div class="view">
<% if (extension(file.path) == ".mp4" || extension(file.path) == ".mov" || extension(file.path) == "webp") { %> <% if (extension(file.path) == ".mp4" || extension(file.path) == ".mov" || extension(file.path) == "webp") { %>
<div class="video"> <div class="video">
<video class="image" autoplay loop muted playsinline loading="lazy"> <video class="image" autoplay loop muted playsinline loading="lazy">
<source src="/uploads/<%= file.path %>" loading="lazy"> <source src="/uploads/<%= file.path %>" loading="lazy">
</video> </video>
<div class="overlay"> <div class="overlay">
<a href="/gifv/<%=file.path %>" onclick="copyA(event)">Copy as GIFv</a> <a href="/gifv/<%=file.path %>" onclick="copyA(event)">Copy as GIFv</a>
</div> </div>
</div> </div>
<% } else if (extension(file.path) == ".gif") { %> <% } else if (extension(file.path) == ".gif") { %>
<div class="video"> <div class="video">
<img class="image" src="/uploads/<%=file.path %>" width="100%" onclick="copyURI(event)" loading="lazy"> <img class="image" src="/uploads/<%=file.path %>" width="100%" onclick="copyURI(event)" loading="lazy">
<div class="overlay"> <div class="overlay">
<a href="/gifv/<%=file.path %>" onclick="copyA(event)">Copy as GIFv</a> <a href="/gifv/<%=file.path %>" onclick="copyA(event)">Copy as GIFv</a>
</div> </div>
</div> </div>
<% } else if (extension(file.path) == ".jpg" || extension(file.path) == ".jpeg" || extension(file.path) == ".png" || extension(file.path) == ".gif" || extension(file.path) == ".webp" ) { %> <% } else if (extension(file.path) == ".jpg" || extension(file.path) == ".jpeg" || extension(file.path) == ".png" || extension(file.path) == ".gif" || extension(file.path) == ".webp" ) { %>
<img class="image" src="/uploads/<%=file.path %>" width="100%" onclick="copyURI(event)" loading="lazy"> <img class="image" src="/uploads/<%=file.path %>" width="100%" onclick="copyURI(event)" loading="lazy">
<% } else {%> <!-- non-media file --> <% } else {%> <!-- non-media file -->
<div class="nonmedia" onclick="copyPath('<%=file.path%>')"> <div class="nonmedia" onclick="copyPath('/uploads/<%=file.path%>')">
<p><%=extension(file.path)%> file</p> <p><%=extension(file.path)%> file</p>
</div> </div>
<% } %> <% } %>
<label><%= file.path %></label> <label><%= file.path %></label>
<button class="destroy" form="delete-<%= file.path %>"></button> <button class="destroy" form="delete-<%= file.path %>"></button>
</div> </div>
</form> </form>
<form name="delete-<%= file.path %>" id="delete-<%= file.path %>" action="<%= file.url %>/delete" method="post"> <form name="delete-<%= file.path %>" id="delete-<%= file.path %>" action="<%= file.url %>/delete" method="post">
</form> </form>
</li> </li>
<% }); %> <% }); %>
</ul> </ul>
</section> </section>
<% } %> <% } %>
</section> </section>
<footer class="info"> <footer class="info">
<p><a href="https://l.nekomimi.pet/project">Created by Wavering Ana</a></p> <p><a href="https://l.nekomimi.pet/project">Created by Wavering Ana</a></p>
<p><a href="https://github.com/WaveringAna/Embedder">Github</a></p> <p><a href="https://github.com/WaveringAna/Embedder">Github</a></p>
</footer> </footer>
<script src="/js/index.js"></script> <script src="/js/index.js"></script>
</body> </body>
</html> </html>

View file

@ -1,37 +1,37 @@
<!doctype html> <!doctype html>
<html lang="en"> <html lang="en">
<head> <head>
<meta charset="utf-8"> <meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1"> <meta name="viewport" content="width=device-width, initial-scale=1">
<title>Embedder</title> <title>Embedder</title>
<link rel="stylesheet" href="/css/base.css"> <link rel="stylesheet" href="/css/base.css">
<link rel="stylesheet" href="/css/index.css"> <link rel="stylesheet" href="/css/index.css">
<link rel="stylesheet" href="/css/login.css"> <link rel="stylesheet" href="/css/login.css">
<link rel="apple-touch-icon" sizes="180x180" href="/apple-touch-icon.png"> <link rel="apple-touch-icon" sizes="180x180" href="/apple-touch-icon.png">
<link rel="icon" type="image/png" sizes="32x32" href="/favicon-32x32.png"> <link rel="icon" type="image/png" sizes="32x32" href="/favicon-32x32.png">
<link rel="icon" type="image/png" sizes="16x16" href="/favicon-16x16.png"> <link rel="icon" type="image/png" sizes="16x16" href="/favicon-16x16.png">
<link rel="manifest" href="/site.webmanifest"> <link rel="manifest" href="/site.webmanifest">
</head> </head>
<body> <body>
<section class="prompt"> <section class="prompt">
<h3>Embedder</h3> <h3>Embedder</h3>
<h1>Sign in</h1> <h1>Sign in</h1>
<form action="/login/password" method="post"> <form action="/login/password" method="post">
<section> <section>
<label for="username">Username</label> <label for="username">Username</label>
<input id="username" name="username" type="text" autocomplete="username" required autofocus> <input id="username" name="username" type="text" autocomplete="username" required autofocus>
</section> </section>
<section> <section>
<label for="current-password">Password</label> <label for="current-password">Password</label>
<input id="current-password" name="password" type="password" autocomplete="current-password" required> <input id="current-password" name="password" type="password" autocomplete="current-password" required>
</section> </section>
<button type="submit">Sign in</button> <button type="submit">Sign in</button>
</form> </form>
<hr> <hr>
</section> </section>
<footer class="info"> <footer class="info">
<p><a href="https://l.nekomimi.pet/project">Created by Wavering Ana</a></p> <p><a href="https://l.nekomimi.pet/project">Created by Wavering Ana</a></p>
<p><a href="https://github.com/WaveringAna/Embedder">Github</a></p> <p><a href="https://github.com/WaveringAna/Embedder">Github</a></p>
</footer> </footer>
</body> </body>
</html> </html>

View file

@ -1,4 +0,0 @@
#!/bin/bash
node db.js
npm start

View file

@ -1,12 +1,12 @@
.env .env
var var
uploads uploads
# Node.js # Node.js
node_modules/ node_modules/
npm-debug.log* npm-debug.log*
# Mac OS X # Mac OS X
.DS_Store .DS_Store
Dockerfile Dockerfile

View file

@ -1,22 +1,22 @@
FROM node:16-alpine AS BUILD_IMAGE FROM node:16-alpine AS BUILD_IMAGE
RUN apk add curl bash RUN apk add curl
RUN curl -sf https://gobinaries.com/tj/node-prune | sh
# Install dependencies
COPY package*.json ./ COPY package*.json ./
RUN npm install RUN npm install
RUN npm prune --production RUN npm prune --production
RUN /usr/local/bin/node-prune
RUN curl -sf https://gobinaries.com/tj/node-prune | sh
FROM node:16-alpine FROM node:16-alpine
COPY --from=BUILD_IMAGE /node_modules ./node_modules COPY --from=BUILD_IMAGE /node_modules ./node_modules
COPY . . COPY /app ./app
COPY package*.json ./
ENV NODE_ENV=production ENV NODE_ENV=production
RUN node db.js RUN node /app/db.js
CMD ["npm", "start"] CMD ["npm", "start"]

View file

@ -21,14 +21,13 @@
}, },
"license": "Unlicense", "license": "Unlicense",
"scripts": { "scripts": {
"start": "node ./app.js" "start": "node ./app/app.js"
}, },
"dependencies": { "dependencies": {
"@ffmpeg-installer/ffmpeg": "^1.1.0", "@ffmpeg-installer/ffmpeg": "^1.1.0",
"@ffprobe-installer/ffprobe": "^1.4.1", "@ffprobe-installer/ffprobe": "^1.4.1",
"connect-sqlite3": "^0.9.13", "connect-sqlite3": "^0.9.13",
"cookie-parser": "~1.4.4", "cookie-parser": "~1.4.4",
"cypress-real-events": "^1.7.4",
"dotenv": "^8.6.0", "dotenv": "^8.6.0",
"ejs": "^3.1.8", "ejs": "^3.1.8",
"express": "~4.16.1", "express": "~4.16.1",
@ -45,6 +44,7 @@
"devDependencies": { "devDependencies": {
"cypress": "^11.1.0", "cypress": "^11.1.0",
"cypress-file-upload": "^5.0.8", "cypress-file-upload": "^5.0.8",
"cypress-real-events": "^1.7.4",
"eslint": "^8.28.0" "eslint": "^8.28.0"
} }
} }