feat: gfycat url #322
This commit is contained in:
parent
5b9b454330
commit
f8cd847588
12 changed files with 3354 additions and 69 deletions
|
@ -0,0 +1,11 @@
|
||||||
|
/*
|
||||||
|
Warnings:
|
||||||
|
|
||||||
|
- You are about to drop the column `format` on the `File` table. All the data in the column will be lost.
|
||||||
|
|
||||||
|
*/
|
||||||
|
-- AlterTable
|
||||||
|
ALTER TABLE "File" DROP COLUMN "format";
|
||||||
|
|
||||||
|
-- DropEnum
|
||||||
|
DROP TYPE "FileNameFormat";
|
|
@ -40,13 +40,6 @@ model Folder {
|
||||||
files File[]
|
files File[]
|
||||||
}
|
}
|
||||||
|
|
||||||
enum FileNameFormat {
|
|
||||||
UUID
|
|
||||||
DATE
|
|
||||||
RANDOM
|
|
||||||
NAME
|
|
||||||
}
|
|
||||||
|
|
||||||
model File {
|
model File {
|
||||||
id Int @id @default(autoincrement())
|
id Int @id @default(autoincrement())
|
||||||
name String
|
name String
|
||||||
|
@ -61,7 +54,6 @@ model File {
|
||||||
embed Boolean @default(false)
|
embed Boolean @default(false)
|
||||||
password String?
|
password String?
|
||||||
invisible InvisibleFile?
|
invisible InvisibleFile?
|
||||||
format FileNameFormat @default(RANDOM)
|
|
||||||
|
|
||||||
user User? @relation(fields: [userId], references: [id], onDelete: SetNull)
|
user User? @relation(fields: [userId], references: [id], onDelete: SetNull)
|
||||||
userId Int?
|
userId Int?
|
||||||
|
|
1501
public/adjectives.txt
Normal file
1501
public/adjectives.txt
Normal file
File diff suppressed because it is too large
Load diff
1750
public/animals.txt
Normal file
1750
public/animals.txt
Normal file
File diff suppressed because it is too large
Load diff
|
@ -103,10 +103,11 @@ export function GeneratorModal({ opened, onClose, title, onSubmit, ...other }) {
|
||||||
<Select
|
<Select
|
||||||
label='Select file name format'
|
label='Select file name format'
|
||||||
data={[
|
data={[
|
||||||
{ value: 'RANDOM', label: 'Random (alphanumeric)' },
|
{ value: 'random', label: 'Random (alphanumeric)' },
|
||||||
{ value: 'DATE', label: 'Date' },
|
{ value: 'date', label: 'Date' },
|
||||||
{ value: 'UUID', label: 'UUID' },
|
{ value: 'uuid', label: 'UUID' },
|
||||||
{ value: 'NAME', label: 'Name (keeps original file name)' },
|
{ value: 'name', label: 'Name (keeps original file name)' },
|
||||||
|
{ value: 'gfycat', label: 'Gfycat' },
|
||||||
]}
|
]}
|
||||||
id='format'
|
id='format'
|
||||||
my='sm'
|
my='sm'
|
||||||
|
|
|
@ -152,10 +152,11 @@ export function OptionsModal({
|
||||||
icon={<IconFileInfo size='1rem' />}
|
icon={<IconFileInfo size='1rem' />}
|
||||||
data={[
|
data={[
|
||||||
{ value: 'default', label: 'Default' },
|
{ value: 'default', label: 'Default' },
|
||||||
{ value: 'RANDOM', label: 'Random' },
|
{ value: 'random', label: 'Random' },
|
||||||
{ value: 'NAME', label: 'Original Name' },
|
{ value: 'name', label: 'Original Name' },
|
||||||
{ value: 'DATE', label: 'Date (format configured by server)' },
|
{ value: 'date', label: 'Date (format configured by server)' },
|
||||||
{ value: 'UUID', label: 'UUID' },
|
{ value: 'uuid', label: 'UUID' },
|
||||||
|
{ value: 'gfycat', label: 'Gfycat' },
|
||||||
]}
|
]}
|
||||||
/>
|
/>
|
||||||
<PasswordInput
|
<PasswordInput
|
||||||
|
|
6
src/lib/format/date.ts
Normal file
6
src/lib/format/date.ts
Normal file
|
@ -0,0 +1,6 @@
|
||||||
|
import dayjs from 'dayjs';
|
||||||
|
import config from 'lib/config';
|
||||||
|
|
||||||
|
export default function date() {
|
||||||
|
return dayjs().format(config.uploader.format_date);
|
||||||
|
}
|
26
src/lib/format/gfycat.ts
Normal file
26
src/lib/format/gfycat.ts
Normal file
|
@ -0,0 +1,26 @@
|
||||||
|
import { readFile } from 'fs/promises';
|
||||||
|
|
||||||
|
export type GfyCatWords = {
|
||||||
|
adjectives: string[];
|
||||||
|
animals: string[];
|
||||||
|
};
|
||||||
|
|
||||||
|
export async function importWords(): Promise<GfyCatWords> {
|
||||||
|
const adjectives = (await readFile('public/adjectives.txt', 'utf-8')).split('\n');
|
||||||
|
const animals = (await readFile('public/animals.txt', 'utf-8')).split('\n');
|
||||||
|
|
||||||
|
return {
|
||||||
|
adjectives,
|
||||||
|
animals,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
function randomWord(words: string[]) {
|
||||||
|
return words[Math.floor(Math.random() * words.length)];
|
||||||
|
}
|
||||||
|
|
||||||
|
export default async function gfycat() {
|
||||||
|
const words = await importWords();
|
||||||
|
|
||||||
|
return `${randomWord(words.adjectives)}${randomWord(words.adjectives)}${randomWord(words.animals)}`;
|
||||||
|
}
|
24
src/lib/format/index.ts
Normal file
24
src/lib/format/index.ts
Normal file
|
@ -0,0 +1,24 @@
|
||||||
|
import date from './date';
|
||||||
|
import gfycat from './gfycat';
|
||||||
|
import random from './random';
|
||||||
|
import uuid from './uuid';
|
||||||
|
|
||||||
|
export type NameFormat = 'random' | 'date' | 'uuid' | 'name' | 'gfycat';
|
||||||
|
export const NameFormats: NameFormat[] = ['random', 'date', 'uuid', 'name', 'gfycat'];
|
||||||
|
export default async function formatFileName(nameFormat: NameFormat, originalName?: string) {
|
||||||
|
console.log(nameFormat, originalName);
|
||||||
|
switch (nameFormat) {
|
||||||
|
case 'random':
|
||||||
|
return random();
|
||||||
|
case 'date':
|
||||||
|
return date();
|
||||||
|
case 'uuid':
|
||||||
|
return uuid();
|
||||||
|
case 'name':
|
||||||
|
return originalName.split('.')[0];
|
||||||
|
case 'gfycat':
|
||||||
|
return gfycat();
|
||||||
|
default:
|
||||||
|
return random();
|
||||||
|
}
|
||||||
|
}
|
6
src/lib/format/random.ts
Normal file
6
src/lib/format/random.ts
Normal file
|
@ -0,0 +1,6 @@
|
||||||
|
import { randomChars } from 'lib/util';
|
||||||
|
import config from 'lib/config';
|
||||||
|
|
||||||
|
export default function random() {
|
||||||
|
return randomChars(config.uploader.length);
|
||||||
|
}
|
5
src/lib/format/uuid.ts
Normal file
5
src/lib/format/uuid.ts
Normal file
|
@ -0,0 +1,5 @@
|
||||||
|
import { randomUUID } from 'crypto';
|
||||||
|
|
||||||
|
export default function uuid() {
|
||||||
|
return randomUUID({ disableEntropyCache: true });
|
||||||
|
}
|
|
@ -1,10 +1,11 @@
|
||||||
import { FileNameFormat, InvisibleFile } from '@prisma/client';
|
import { InvisibleFile } from '@prisma/client';
|
||||||
import { randomUUID } from 'crypto';
|
import { randomUUID } from 'crypto';
|
||||||
import dayjs from 'dayjs';
|
import dayjs from 'dayjs';
|
||||||
import { readdir, readFile, unlink, writeFile } from 'fs/promises';
|
import { readdir, readFile, unlink, writeFile } from 'fs/promises';
|
||||||
import zconfig from 'lib/config';
|
import zconfig from 'lib/config';
|
||||||
import datasource from 'lib/datasource';
|
import datasource from 'lib/datasource';
|
||||||
import { sendUpload } from 'lib/discord';
|
import { sendUpload } from 'lib/discord';
|
||||||
|
import formatFileName, { NameFormat, NameFormats } from 'lib/format';
|
||||||
import Logger from 'lib/logger';
|
import Logger from 'lib/logger';
|
||||||
import { NextApiReq, NextApiRes, withZipline } from 'lib/middleware/withZipline';
|
import { NextApiReq, NextApiRes, withZipline } from 'lib/middleware/withZipline';
|
||||||
import prisma from 'lib/prisma';
|
import prisma from 'lib/prisma';
|
||||||
|
@ -54,8 +55,8 @@ async function handler(req: NextApiReq, res: NextApiRes) {
|
||||||
if (!expiry) return res.badRequest('invalid date (UPLOADER_DEFAULT_EXPIRATION)');
|
if (!expiry) return res.badRequest('invalid date (UPLOADER_DEFAULT_EXPIRATION)');
|
||||||
}
|
}
|
||||||
|
|
||||||
const rawFormat = ((req.headers.format || '') as string).toUpperCase() || zconfig.uploader.default_format;
|
const rawFormat = ((req.headers['format'] as string) || zconfig.uploader.default_format).toLowerCase();
|
||||||
const format: FileNameFormat = Object.keys(FileNameFormat).includes(rawFormat) && FileNameFormat[rawFormat];
|
const format = NameFormats.includes(rawFormat as NameFormat) ? rawFormat : 'random';
|
||||||
|
|
||||||
const imageCompressionPercent = req.headers['image-compression-percent']
|
const imageCompressionPercent = req.headers['image-compression-percent']
|
||||||
? Number(req.headers['image-compression-percent'])
|
? Number(req.headers['image-compression-percent'])
|
||||||
|
@ -124,25 +125,7 @@ async function handler(req: NextApiReq, res: NextApiRes) {
|
||||||
const ext = filename.split('.').length === 1 ? '' : filename.split('.').pop();
|
const ext = filename.split('.').length === 1 ? '' : filename.split('.').pop();
|
||||||
if (zconfig.uploader.disabled_extensions.includes(ext))
|
if (zconfig.uploader.disabled_extensions.includes(ext))
|
||||||
return res.error('disabled extension recieved: ' + ext);
|
return res.error('disabled extension recieved: ' + ext);
|
||||||
let fileName: string;
|
let fileName = await formatFileName(format, filename);
|
||||||
|
|
||||||
switch (format) {
|
|
||||||
case FileNameFormat.RANDOM:
|
|
||||||
fileName = randomChars(zconfig.uploader.length);
|
|
||||||
break;
|
|
||||||
case FileNameFormat.DATE:
|
|
||||||
fileName = dayjs().format(zconfig.uploader.format_date);
|
|
||||||
break;
|
|
||||||
case FileNameFormat.UUID:
|
|
||||||
fileName = randomUUID({ disableEntropyCache: true });
|
|
||||||
break;
|
|
||||||
case FileNameFormat.NAME:
|
|
||||||
fileName = filename.split('.')[0];
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
fileName = randomChars(zconfig.uploader.length);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
let password = null;
|
let password = null;
|
||||||
if (req.headers.password) {
|
if (req.headers.password) {
|
||||||
|
@ -158,7 +141,6 @@ async function handler(req: NextApiReq, res: NextApiRes) {
|
||||||
mimetype,
|
mimetype,
|
||||||
userId: user.id,
|
userId: user.id,
|
||||||
embed: !!req.headers.embed,
|
embed: !!req.headers.embed,
|
||||||
format,
|
|
||||||
password,
|
password,
|
||||||
expiresAt: expiry,
|
expiresAt: expiry,
|
||||||
maxViews: fileMaxViews,
|
maxViews: fileMaxViews,
|
||||||
|
@ -250,35 +232,16 @@ async function handler(req: NextApiReq, res: NextApiRes) {
|
||||||
const ext = file.originalname.split('.').length === 1 ? '' : file.originalname.split('.').pop();
|
const ext = file.originalname.split('.').length === 1 ? '' : file.originalname.split('.').pop();
|
||||||
if (zconfig.uploader.disabled_extensions.includes(ext))
|
if (zconfig.uploader.disabled_extensions.includes(ext))
|
||||||
return res.badRequest(`file[${i}]: disabled extension recieved: ${ext}`);
|
return res.badRequest(`file[${i}]: disabled extension recieved: ${ext}`);
|
||||||
let fileName: string;
|
let fileName = await formatFileName(format, file.originalname);
|
||||||
|
console.log(fileName);
|
||||||
switch (format) {
|
if (req.headers['x-zipline-filename']) {
|
||||||
case FileNameFormat.RANDOM:
|
fileName = req.headers['x-zipline-filename'] as string;
|
||||||
fileName = randomChars(zconfig.uploader.length);
|
const existing = await prisma.file.findFirst({
|
||||||
break;
|
where: {
|
||||||
case FileNameFormat.DATE:
|
name: fileName,
|
||||||
fileName = dayjs().format(zconfig.uploader.format_date);
|
},
|
||||||
break;
|
});
|
||||||
case FileNameFormat.UUID:
|
if (existing) return res.badRequest(`file[${i}]: filename already exists: '${fileName}'`);
|
||||||
fileName = randomUUID({ disableEntropyCache: true });
|
|
||||||
break;
|
|
||||||
case FileNameFormat.NAME:
|
|
||||||
fileName = file.originalname.split('.')[0];
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
if (req.headers['x-zipline-filename']) {
|
|
||||||
fileName = req.headers['x-zipline-filename'] as string;
|
|
||||||
const existing = await prisma.file.findFirst({
|
|
||||||
where: {
|
|
||||||
name: fileName,
|
|
||||||
},
|
|
||||||
});
|
|
||||||
if (existing) return res.badRequest(`file[${i}]: filename already exists: '${fileName}'`);
|
|
||||||
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
fileName = randomChars(zconfig.uploader.length);
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
let password = null;
|
let password = null;
|
||||||
|
@ -294,7 +257,6 @@ async function handler(req: NextApiReq, res: NextApiRes) {
|
||||||
mimetype: req.headers.uploadtext ? 'text/plain' : compressionUsed ? 'image/jpeg' : file.mimetype,
|
mimetype: req.headers.uploadtext ? 'text/plain' : compressionUsed ? 'image/jpeg' : file.mimetype,
|
||||||
userId: user.id,
|
userId: user.id,
|
||||||
embed: !!req.headers.embed,
|
embed: !!req.headers.embed,
|
||||||
format,
|
|
||||||
password,
|
password,
|
||||||
expiresAt: expiry,
|
expiresAt: expiry,
|
||||||
maxViews: fileMaxViews,
|
maxViews: fileMaxViews,
|
||||||
|
|
Loading…
Reference in a new issue