aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/api/databaseMigration.js59
-rw-r--r--src/api/routes/service/versionGET.js15
-rw-r--r--src/api/routes/uploads/uploadPOST.js2
-rw-r--r--src/api/structures/Server.js3
-rw-r--r--src/api/utils/Util.js8
-rw-r--r--src/setup.js42
-rw-r--r--src/site/assets/images/blank2.jpgbin0 -> 14245 bytes
-rw-r--r--src/site/components/grid/Grid.vue6
-rw-r--r--src/site/components/navbar/Navbar.vue9
9 files changed, 104 insertions, 40 deletions
diff --git a/src/api/databaseMigration.js b/src/api/databaseMigration.js
index d95605d..4bd45b7 100644
--- a/src/api/databaseMigration.js
+++ b/src/api/databaseMigration.js
@@ -3,6 +3,13 @@
/* eslint-disable no-console */
const nodePath = require('path');
const moment = require('moment');
+const jetpack = require('fs-jetpack');
+const { path } = require('fs-jetpack');
+const sharp = require('sharp');
+const ffmpeg = require('fluent-ffmpeg');
+
+const imageExtensions = ['.jpg', '.jpeg', '.bmp', '.gif', '.png', '.webp'];
+const videoExtensions = ['.webm', '.mp4', '.wmv', '.avi', '.mov'];
const oldDb = require('knex')({
client: 'sqlite3',
@@ -45,6 +52,10 @@ const start = async () => {
console.log('Starting migration, this may take a few minutes...'); // Because I half assed it
console.log('Please do NOT kill the process. Wait for it to finish.');
+ await jetpack.removeAsync(nodePath.join(__dirname, '..', '..', 'uploads', 'thumbs'));
+ await jetpack.dirAsync(nodePath.join(__dirname, '..', '..', 'uploads', 'thumbs', 'square'));
+ console.log('Finished deleting old thumbnails to create new ones');
+
const users = await oldDb.table('users').where('username', '<>', 'root');
for (const user of users) {
const now = moment.utc().toDate();
@@ -116,6 +127,13 @@ const start = async () => {
albumId: file.albumid,
fileId: file.id,
});
+
+ const filename = file.name;
+ if (!jetpack.exists(nodePath.join(__dirname, '..', '..', 'uploads', filename))) continue;
+ const ext = nodePath.extname(filename).toLowerCase();
+ const output = `${filename.slice(0, -ext.length)}.webp`;
+ if (imageExtensions.includes(ext)) await generateThumbnailForImage(filename, output);
+ if (videoExtensions.includes(ext)) generateThumbnailForVideo(filename);
}
await newDb.batchInsert('files', filesToInsert, 20);
await newDb.batchInsert('albumsFiles', albumsFilesToInsert, 20);
@@ -125,4 +143,45 @@ const start = async () => {
process.exit(0);
};
+const generateThumbnailForImage = async (filename, output) => {
+ try {
+ const file = await jetpack.readAsync(nodePath.join(__dirname, '..', '..', 'uploads', filename), 'buffer');
+ await sharp(file)
+ .resize(64, 64)
+ .toFormat('webp')
+ .toFile(nodePath.join(__dirname, '..', '..', 'uploads', 'thumbs', 'square', output));
+ await sharp(file)
+ .resize(225, null)
+ .toFormat('webp')
+ .toFile(nodePath.join(__dirname, '..', '..', 'uploads', 'thumbs', output));
+ console.log('finished', filename);
+ } catch (error) {
+ console.log('error', filename);
+ }
+};
+
+const generateThumbnailForVideo = filename => {
+ try {
+ ffmpeg(nodePath.join(__dirname, '..', '..', 'uploads', filename))
+ .thumbnail({
+ timestamps: [0],
+ filename: '%b.png',
+ folder: nodePath.join(__dirname, '..', '..', 'uploads', 'thumbs', 'square'),
+ size: '64x64'
+ })
+ .on('error', error => console.error(error.message));
+ ffmpeg(nodePath.join(__dirname, '..', '..', 'uploads', filename))
+ .thumbnail({
+ timestamps: [0],
+ filename: '%b.png',
+ folder: nodePath.join(__dirname, '..', '..', 'uploads', 'thumbs'),
+ size: '150x?'
+ })
+ .on('error', error => console.error(error.message));
+ console.log('finished', filename);
+ } catch (error) {
+ console.log('error', filename);
+ }
+};
+
start();
diff --git a/src/api/routes/service/versionGET.js b/src/api/routes/service/versionGET.js
new file mode 100644
index 0000000..dfb994a
--- /dev/null
+++ b/src/api/routes/service/versionGET.js
@@ -0,0 +1,15 @@
+const Route = require('../../structures/Route');
+
+class versionGET extends Route {
+ constructor() {
+ super('/version', 'get', { bypassAuth: true });
+ }
+
+ run(req, res) {
+ return res.json({
+ version: process.env.npm_package_version
+ });
+ }
+}
+
+module.exports = versionGET;
diff --git a/src/api/routes/uploads/uploadPOST.js b/src/api/routes/uploads/uploadPOST.js
index 99f5ee5..3e67293 100644
--- a/src/api/routes/uploads/uploadPOST.js
+++ b/src/api/routes/uploads/uploadPOST.js
@@ -117,6 +117,7 @@ class uploadPOST extends Route {
this.saveFileToAlbum(db, albumId, insertedId);
}
+ uploadedFile = Util.constructFilePublicLink(uploadedFile);
return res.status(201).send({
message: 'Sucessfully uploaded the file.',
...uploadedFile,
@@ -125,6 +126,7 @@ class uploadPOST extends Route {
}
fileExists(res, exists, filename) {
+ exists = Util.constructFilePublicLink(exists);
res.json({
message: 'Successfully uploaded the file.',
name: exists.name,
diff --git a/src/api/structures/Server.js b/src/api/structures/Server.js
index c8537fb..7f1b4d5 100644
--- a/src/api/structures/Server.js
+++ b/src/api/structures/Server.js
@@ -103,9 +103,10 @@ class Server {
jetpack.dir('uploads/thumbs/square');
this.registerAllTheRoutes();
this.serveNuxt();
- this.server.listen(this.port, () => {
+ const server = this.server.listen(this.port, () => {
log.success(`Backend ready and listening on port ${this.port}`);
});
+ server.setTimeout(600000);
}
}
diff --git a/src/api/utils/Util.js b/src/api/utils/Util.js
index 905948a..ee4c748 100644
--- a/src/api/utils/Util.js
+++ b/src/api/utils/Util.js
@@ -175,7 +175,13 @@ class Util {
}
}
- static isAuthorized(req) {
+ static async isAuthorized(req) {
+ if (req.headers.token) {
+ const user = await db.table('users').where({ apiKey: req.headers.token }).first();
+ if (!user || !user.enabled) return false;
+ return user;
+ }
+
if (!req.headers.authorization) return false;
const token = req.headers.authorization.split(' ')[1];
if (!token) return false;
diff --git a/src/setup.js b/src/setup.js
index 91eaa1c..2f9dee2 100644
--- a/src/setup.js
+++ b/src/setup.js
@@ -16,16 +16,11 @@ async function start() {
const wizard = [
{
type: 'input',
- query: 'Port to run the API in:',
+ query: 'Port to run lolisafe in:',
handle: 'SERVER_PORT',
},
{
type: 'input',
- query: 'Port to run the Website in when in dev mode:',
- handle: 'WEBSITE_PORT',
- },
- {
- type: 'input',
query: 'Full domain this instance is gonna be running on (Ex: https://lolisafe.moe):',
handle: 'DOMAIN',
},
@@ -41,13 +36,6 @@ async function start() {
},
{
type: 'confirm',
- query: 'Generate thumbnails for images/videos? (Requires ffmpeg installed and in your PATH)',
- handle: 'GENERATE_THUMBNAILS',
- accept: 'y',
- deny: 'n',
- },
- {
- type: 'confirm',
query: 'Allow users to download entire albums in ZIP format?',
handle: 'GENERATE_ZIPS',
accept: 'y',
@@ -55,31 +43,14 @@ async function start() {
},
{
type: 'confirm',
- query: 'Serve files with node?',
- handle: 'SERVE_WITH_NODE',
- accept: 'y',
- deny: 'n',
- },
- {
- type: 'input',
- query: 'Base number of characters for generated file URLs (12 should be good enough):',
- handle: 'GENERATED_FILENAME_LENGTH',
- },
- {
- type: 'input',
- query: 'Base number of characters for generated album URLs (6 should be enough):',
- handle: 'GENERATED_ALBUM_LENGTH',
- },
- {
- type: 'confirm',
- query: 'Run lolisafe in public mode? (People will be able to upload without an account)',
+ query: 'Allow people to upload files without an account?',
handle: 'PUBLIC_MODE',
accept: 'y',
deny: 'n',
},
{
type: 'confirm',
- query: 'Enable user signup for new accounts?',
+ query: 'Allow people to create new accounts?',
handle: 'USER_ACCOUNTS',
accept: 'y',
deny: 'n',
@@ -131,6 +102,11 @@ async function start() {
let envfile = '';
const defaultSettings = {
+ GENERATED_FILENAME_LENGTH: 12,
+ GENERATED_ALBUM_LENGTH: 6,
+ WEBSITE_PORT: 5001,
+ SERVE_WITH_NODE: true,
+ GENERATE_THUMBNAILS: true,
CHUNK_SIZE: 90,
ROUTE_PREFIX: '/api',
RATE_LIMIT_WINDOW: 2,
@@ -158,8 +134,6 @@ async function start() {
console.log('=============================================');
console.log('== .env file generated successfully. ==');
console.log('=============================================');
- console.log('== Run `yarn migrate` and `yarn seed` next ==');
- console.log('=============================================');
console.log();
}
diff --git a/src/site/assets/images/blank2.jpg b/src/site/assets/images/blank2.jpg
new file mode 100644
index 0000000..dbf57ad
--- /dev/null
+++ b/src/site/assets/images/blank2.jpg
Binary files differ
diff --git a/src/site/components/grid/Grid.vue b/src/site/components/grid/Grid.vue
index 1b62097..1e427fc 100644
--- a/src/site/components/grid/Grid.vue
+++ b/src/site/components/grid/Grid.vue
@@ -152,6 +152,12 @@
</div>
</template>
</b-table>
+ <button
+ v-if="moreFiles"
+ class="button is-primary mt2"
+ @click="loadMoreFiles">
+ Load more
+ </button>
</div>
<b-modal :active.sync="isAlbumsModalActive" scroll="keep">
<ImageInfo :file="modalData.file" />
diff --git a/src/site/components/navbar/Navbar.vue b/src/site/components/navbar/Navbar.vue
index fb78631..0f82200 100644
--- a/src/site/components/navbar/Navbar.vue
+++ b/src/site/components/navbar/Navbar.vue
@@ -45,11 +45,12 @@
</router-link>
</b-navbar-item>
<b-navbar-item tag="div">
- <a
- class="navbar-item"
- @click="logOut">
+ <router-link
+ to="/"
+ class="navbar-item no-active"
+ @click.native="logOut">
Logout
- </a>
+ </router-link>
</b-navbar-item>
</template>
<template v-else>