diff options
Diffstat (limited to 'src')
| -rw-r--r-- | src/api/databaseMigration.js | 59 | ||||
| -rw-r--r-- | src/api/routes/service/versionGET.js | 15 | ||||
| -rw-r--r-- | src/api/routes/uploads/uploadPOST.js | 2 | ||||
| -rw-r--r-- | src/api/structures/Server.js | 3 | ||||
| -rw-r--r-- | src/api/utils/Util.js | 8 | ||||
| -rw-r--r-- | src/setup.js | 42 | ||||
| -rw-r--r-- | src/site/assets/images/blank2.jpg | bin | 0 -> 14245 bytes | |||
| -rw-r--r-- | src/site/components/grid/Grid.vue | 6 | ||||
| -rw-r--r-- | src/site/components/navbar/Navbar.vue | 9 |
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 Binary files differnew file mode 100644 index 0000000..dbf57ad --- /dev/null +++ b/src/site/assets/images/blank2.jpg 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> |