@ -0,0 +1,13 @@ | |||
# editorconfig.org | |||
root = true | |||
[*] | |||
indent_size = 2 | |||
indent_style = space | |||
end_of_line = lf | |||
charset = utf-8 | |||
trim_trailing_whitespace = true | |||
insert_final_newline = true | |||
[*.md] | |||
trim_trailing_whitespace = false |
@ -0,0 +1,15 @@ | |||
HOST=localhost | |||
PORT=3333 | |||
NODE_ENV=development | |||
APP_URL=http://${HOST}:${PORT} | |||
CACHE_VIEWS=false | |||
APP_KEY= | |||
DB_CONNECTION=mysql | |||
DB_HOST=127.0.0.1 | |||
DB_PORT=3306 | |||
DB_USER=root | |||
DB_PASSWORD= | |||
DB_DATABASE=adonis | |||
SESSION_DRIVER=cookie | |||
HASH_DRIVER=bcrypt | |||
auth=test |
@ -0,0 +1,27 @@ | |||
# Node modules | |||
node_modules | |||
package-lock.json | |||
# Adonis directory for storing tmp files | |||
tmp | |||
# Environment variables, never commit this file | |||
.env | |||
# The development sqlite file | |||
database/development.sqlite | |||
# VSCode & Webstorm history directories | |||
.history | |||
.idea | |||
# MacOS useless file | |||
.DS_Store | |||
# video files | |||
public/uploads/*.mp4 | |||
public/uploads/*.mp3 | |||
public/uploads/*.flac | |||
# Thumbnail | |||
public/Thumbnail/*.* |
@ -0,0 +1,5 @@ | |||
# Jeff downloader | |||
Jeff downloader is a website to download from [hundreds](https://ytdl-org.github.io/youtube-dl/supportedsites.html) of website using [youtube-dl](https://ytdl-org.github.io/youtube-dl/index.html) | |||
You can find a hosted version on https://namejeff.xyz/ |
@ -0,0 +1,21 @@ | |||
'use strict' | |||
/* | |||
|-------------------------------------------------------------------------- | |||
| Ace Commands | |||
|-------------------------------------------------------------------------- | |||
| | |||
| The ace file is just a regular Javascript file but with no extension. You | |||
| can call `node ace` followed by the command name and it just works. | |||
| | |||
| Also you can use `adonis` followed by the command name, since the adonis | |||
| global proxy all the ace commands. | |||
| | |||
*/ | |||
const { Ignitor } = require('@adonisjs/ignitor') | |||
new Ignitor(require('@adonisjs/fold')) | |||
.appRoot(__dirname) | |||
.fireAce() | |||
.catch(console.error) |
@ -0,0 +1,179 @@ | |||
'use strict' | |||
const youtubedl = require('youtube-dl') | |||
const fs = require('fs') | |||
const ffmpeg = require('fluent-ffmpeg') | |||
const timestamp = require('time-stamp') | |||
let viewCounter = 0; | |||
let files = []; | |||
let day; | |||
let month; | |||
let announcement = 'Twitter download seems to work fine now!'; | |||
class DownloadController { | |||
async index ({ view, response }) { | |||
// Get date for some event | |||
let today = new Date(); | |||
day = today.getDay(); | |||
month = today.getMonth(); | |||
viewCounter++; | |||
if (response.request.url == '/legacy') return view.render('legacy', { title: 'le epic downloader v0.11.3', viewCounter: viewCounter, day: day, month: month, announcement: announcement}); | |||
files = []; | |||
let file = [] | |||
for (let f of fs.readdirSync('./public/uploads')) { | |||
file.push(f) | |||
} | |||
// get the 5 most recent files | |||
file = file.sort(function(a, b) { | |||
if ((a || b).endsWith('.mp4') && !(a || b).startsWith('HIDE')) { | |||
let time1 = fs.statSync(`./public/uploads/${b}`).ctime; | |||
let time2 = fs.statSync(`./public/uploads/${a}`).ctime; | |||
if (time1 < time2) return -1; | |||
if (time1 > time2) return 1; | |||
} | |||
return 0; | |||
}).slice(0, 5) | |||
file.forEach((file) => { | |||
// If mp4 and is not to be hidden from the recent feed | |||
if (file.endsWith('.mp4') && !file.startsWith('HIDE')) { | |||
let fileInfo = fs.statSync(`./public/uploads/${file}`); | |||
// Take screenshot at the first frame of the mp4 file | |||
ffmpeg(`./public/uploads/${file}`) | |||
.takeScreenshots({ count: 1, timemarks: [ 1 ], size: '720x480', filename: file + '.png' }, 'public/thumbnail') | |||
.on('error', (err) => { | |||
console.error(err); | |||
return; | |||
}); | |||
if (fs.existsSync(`./public/thumbnail/${file}.png`)) { | |||
// Get the image as base64 | |||
let imgData = fs.readFileSync(`./public/thumbnail/${file}.png`).toString('base64'); | |||
if (imgData) { | |||
// Send file name, file size in MB relative path for the file and base64 of the image | |||
files.push({ name: file, size: (fileInfo.size / 1000000.0).toFixed(2), location: `uploads/${file}`, img: imgData }); | |||
fs.unlinkSync(`./public/thumbnail/${file}.png`); | |||
} | |||
} | |||
// If mp3 or flac and not to be hidden from the recent feed | |||
} else if ((file.endsWith('.mp3') || file.endsWith('.flac')) && !file.startsWith('HIDE')) { | |||
let fileInfo = fs.statSync(`./public/uploads/${file}`); | |||
// Send file name, file size in MB relative path for the file and base64 of music.png | |||
files.push({ name: file, size: (fileInfo.size / 1000000.0).toFixed(2), location: `uploads/${file}`, img: fs.readFileSync(`./public/asset/music.png`).toString('base64') }); | |||
} | |||
}); | |||
return view.render('index', { title: 'le epic downloader v0.11.3', viewCounter: viewCounter, file: files, day: day, month: month, announcement: announcement }); | |||
} | |||
async download({ view, request, response }) { | |||
let page = 'index'; | |||
if (response.request.url == '/legacy') page = 'legacy'; | |||
// To be honest i forgot what it does, but i think i need it | |||
response.implicitEnd = false | |||
let option, DLFile | |||
// Get form input | |||
let data = { | |||
url: request.input('URL'), | |||
quality: request.input('quality'), | |||
format: request.input('format'), | |||
alt: request.input('alt'), | |||
feed: request.input('feed') | |||
} | |||
if (!data.url) { | |||
return view.render(page, { | |||
title: 'le epic downloader v0.11.3', | |||
viewCounter: viewCounter, | |||
file: files, | |||
day: day, month: month, announcement: announcement , | |||
error: true, | |||
errormsg: 'bruh moment, you didin\'t input a link.' | |||
}); | |||
} | |||
// Youtube-dl quality settings | |||
if (data.quality == 'small') | |||
option = 'worst' | |||
else | |||
option = 'best' | |||
// If alt download ( Quality settings and file format option doesn't work here ) | |||
if (data.alt) { | |||
if (fs.existsSync('./public/uploads/alt.mp4')) { | |||
fs.unlink('./public/uploads/alt.mp4', (err) => { | |||
if (err); | |||
}); | |||
} | |||
return youtubedl.exec(data.url, ['--format=mp4', '-o', `public/uploads/alt.mp4`], {}, function(err, output) { | |||
if (err) { | |||
return view.render(page, { | |||
title: 'le epic downloader v0.11.3', | |||
viewCounter: viewCounter, | |||
file: files, | |||
day: day, month: month, announcement: announcement , | |||
error: true, | |||
errormsg: 'bruh moment, you didin\'t input a valid link.' | |||
}); | |||
} | |||
return response.attachment('./public/uploads/alt.mp4'); | |||
}); | |||
} else { | |||
// Download as mp4 | |||
let video = youtubedl(data.url, ['--format=mp4', '-f', option]); | |||
video.on('error', function(err) { | |||
console.error(err) | |||
return view.render(page, { | |||
title: 'le epic downloader v0.11.3', | |||
viewCounter: viewCounter, | |||
file: files, | |||
day: day, month: month, announcement: announcement , | |||
error: true, | |||
errormsg: 'bruh moment, you didin\'t input a valid link.' | |||
}); | |||
}) | |||
video.on('info', function(info) { | |||
// Set file name | |||
let title = info.title; | |||
DLFile = `${timestamp('DD_MM_YYYY')}${title.slice(0,10).replace(/\s/g, '_')}.${info.ext}`; | |||
// If no title use the ID | |||
if (title == '_') title = `_${info.id}`; | |||
// If user want to hide from the feed | |||
if (data.feed == 'on') | |||
DLFile = `HIDE${timestamp('DD_MM_YYYY')}${title.slice(0,10).replace(/\s/g, '_')}.${info.ext}`; | |||
DLFile = DLFile.replace(/[()]/g, '_'); | |||
video.pipe(fs.createWriteStream(`./public/uploads/${DLFile}`)); | |||
}); | |||
video.on('end', function() { | |||
if (data.format == 'mp4') { | |||
// If user requested mp4 directly attach the file | |||
return response.attachment(`./public/uploads/${DLFile}`) | |||
} else { | |||
// If user requested an audio format, convert it | |||
ffmpeg(`./public/uploads/${DLFile}`) | |||
.noVideo() | |||
.audioChannels('2') | |||
.audioFrequency('44100') | |||
.audioBitrate('320k') | |||
.format(data.format) | |||
.save(`./public/uploads/${DLFile}.${data.format}`) | |||
.on('end', () => { | |||
fs.unlinkSync(`./public/uploads/${DLFile}`); | |||
return response.attachment(`./public/uploads/${DLFile}.${data.format}`); | |||
}) | |||
} | |||
}); | |||
} | |||
} | |||
} | |||
module.exports = DownloadController |
@ -0,0 +1,17 @@ | |||
'use strict' | |||
class ConvertEmptyStringsToNull { | |||
async handle ({ request }, next) { | |||
if (Object.keys(request.body).length) { | |||
request.body = Object.assign( | |||
...Object.keys(request.body).map(key => ({ | |||
[key]: request.body[key] !== '' ? request.body[key] : null | |||
})) | |||
) | |||
} | |||
await next() | |||
} | |||
} | |||
module.exports = ConvertEmptyStringsToNull |
@ -0,0 +1,16 @@ | |||
'use strict' | |||
class NoTimestamp { | |||
register (Model) { | |||
Object.defineProperties(Model, { | |||
createdAtColumn: { | |||
get: () => null, | |||
}, | |||
updatedAtColumn: { | |||
get: () => null, | |||
}, | |||
}) | |||
} | |||
} | |||
module.exports = NoTimestamp |
@ -0,0 +1,39 @@ | |||
'use strict' | |||
/** @type {import('@adonisjs/framework/src/Hash')} */ | |||
const Hash = use('Hash') | |||
/** @type {typeof import('@adonisjs/lucid/src/Lucid/Model')} */ | |||
const Model = use('Model') | |||
class User extends Model { | |||
static boot () { | |||
super.boot() | |||
/** | |||
* A hook to hash the user password before saving | |||
* it to the database. | |||
*/ | |||
this.addHook('beforeSave', async (userInstance) => { | |||
if (userInstance.dirty.password) { | |||
userInstance.password = await Hash.make(userInstance.password) | |||
} | |||
}) | |||
} | |||
/** | |||
* A relationship on tokens is required for auth to | |||
* work. Since features like `refreshTokens` or | |||
* `rememberToken` will be saved inside the | |||
* tokens table. | |||
* | |||
* @method tokens | |||
* | |||
* @return {Object} | |||
*/ | |||
tokens () { | |||
return this.hasMany('App/Models/Token') | |||
} | |||
} | |||
module.exports = User |
@ -0,0 +1,243 @@ | |||
'use strict' | |||
/** @type {import('@adonisjs/framework/src/Env')} */ | |||
const Env = use('Env') | |||
module.exports = { | |||
/* | |||
|-------------------------------------------------------------------------- | |||
| Application Name | |||
|-------------------------------------------------------------------------- | |||
| | |||
| This value is the name of your application and can be used when you | |||
| need to place the application's name in a email, view or | |||
| other location. | |||
| | |||
*/ | |||
name: Env.get('APP_NAME', 'AdonisJs'), | |||
/* | |||
|-------------------------------------------------------------------------- | |||
| App Key | |||
|-------------------------------------------------------------------------- | |||
| | |||
| App key is a randomly generated 16 or 32 characters long string required | |||
| to encrypted cookies, sessions and other sensitive data. | |||
| | |||
*/ | |||
appKey: Env.getOrFail('APP_KEY'), | |||
http: { | |||
/* | |||
|-------------------------------------------------------------------------- | |||
| Allow Method Spoofing | |||
|-------------------------------------------------------------------------- | |||
| | |||
| Method spoofing allows you to make requests by spoofing the http verb. | |||
| Which means you can make a GET request but instruct the server to | |||
| treat as a POST or PUT request. If you want this feature, set the | |||
| below value to true. | |||
| | |||
*/ | |||
allowMethodSpoofing: true, | |||
/* | |||
|-------------------------------------------------------------------------- | |||
| Trust Proxy | |||
|-------------------------------------------------------------------------- | |||
| | |||
| Trust proxy defines whether X-Forwarded-* headers should be trusted or not. | |||
| When your application is behind a proxy server like nginx, these values | |||
| are set automatically and should be trusted. Apart from setting it | |||
| to true or false Adonis supports a handful of ways to allow proxy | |||
| values. Read documentation for that. | |||
| | |||
*/ | |||
trustProxy: false, | |||
/* | |||
|-------------------------------------------------------------------------- | |||
| Subdomains | |||
|-------------------------------------------------------------------------- | |||
| | |||
| Offset to be used for returning subdomains for a given request. For | |||
| majority of applications it will be 2, until you have nested | |||
| sudomains. | |||
| cheatsheet.adonisjs.com - offset - 2 | |||
| virk.cheatsheet.adonisjs.com - offset - 3 | |||
| | |||
*/ | |||
subdomainOffset: 2, | |||
/* | |||
|-------------------------------------------------------------------------- | |||
| JSONP Callback | |||
|-------------------------------------------------------------------------- | |||
| | |||
| Default jsonp callback to be used when callback query string is missing | |||
| in request url. | |||
| | |||
*/ | |||
jsonpCallback: 'callback', | |||
/* | |||
|-------------------------------------------------------------------------- | |||
| Etag | |||
|-------------------------------------------------------------------------- | |||
| | |||
| Set etag on all HTTP responses. In order to disable for selected routes, | |||
| you can call the `response.send` with an options object as follows. | |||
| | |||
| response.send('Hello', { ignoreEtag: true }) | |||
| | |||
*/ | |||
etag: false | |||
}, | |||
views: { | |||
/* | |||
|-------------------------------------------------------------------------- | |||
| Cache Views | |||
|-------------------------------------------------------------------------- | |||
| | |||
| Define whether or not to cache the compiled view. Set it to true in | |||
| production to optimize view loading time. | |||
| | |||
*/ | |||
cache: Env.get('CACHE_VIEWS', true) | |||
}, | |||
static: { | |||
/* | |||
|-------------------------------------------------------------------------- | |||
| Dot Files | |||
|-------------------------------------------------------------------------- | |||
| | |||
| Define how to treat dot files when trying to serve static resources. | |||
| By default it is set to ignore, which will pretend that dotfiles | |||
| do not exist. | |||
| | |||
| Can be one of the following | |||
| ignore, deny, allow | |||
| | |||
*/ | |||
dotfiles: 'ignore', | |||
/* | |||
|-------------------------------------------------------------------------- | |||
| ETag | |||
|-------------------------------------------------------------------------- | |||
| | |||
| Enable or disable etag generation | |||
| | |||
*/ | |||
etag: true, | |||
/* | |||
|-------------------------------------------------------------------------- | |||
| Extensions | |||
|-------------------------------------------------------------------------- | |||
| | |||
| Set file extension fallbacks. When set, if a file is not found, the given | |||
| extensions will be added to the file name and search for. The first | |||
| that exists will be served. Example: ['html', 'htm']. | |||
| | |||
*/ | |||
extensions: false | |||
}, | |||
locales: { | |||
/* | |||
|-------------------------------------------------------------------------- | |||
| Loader | |||
|-------------------------------------------------------------------------- | |||
| | |||
| The loader to be used for fetching and updating locales. Below is the | |||
| list of available options. | |||
| | |||
| file, database | |||
| | |||
*/ | |||
loader: 'file', | |||
/* | |||
|-------------------------------------------------------------------------- | |||
| Default Locale | |||
|-------------------------------------------------------------------------- | |||
| | |||
| Default locale to be used by Antl provider. You can always switch drivers | |||
| in runtime or use the official Antl middleware to detect the driver | |||
| based on HTTP headers/query string. | |||
| | |||
*/ | |||
locale: 'en' | |||
}, | |||
logger: { | |||
/* | |||
|-------------------------------------------------------------------------- | |||
| Transport | |||
|-------------------------------------------------------------------------- | |||
| | |||
| Transport to be used for logging messages. You can have multiple | |||
| transports using same driver. | |||
| | |||
| Available drivers are: `file` and `console`. | |||
| | |||
*/ | |||
transport: 'console', | |||
/* | |||
|-------------------------------------------------------------------------- | |||
| Console Transport | |||
|-------------------------------------------------------------------------- | |||
| | |||
| Using `console` driver for logging. This driver writes to `stdout` | |||
| and `stderr` | |||
| | |||
*/ | |||
console: { | |||
driver: 'console', | |||
name: 'adonis-app', | |||
level: 'info' | |||
}, | |||
/* | |||
|-------------------------------------------------------------------------- | |||
| File Transport | |||
|-------------------------------------------------------------------------- | |||
| | |||
| File transport uses file driver and writes log messages for a given | |||
| file inside `tmp` directory for your app. | |||
| | |||
| For a different directory, set an absolute path for the filename. | |||
| | |||
*/ | |||
file: { | |||
driver: 'file', | |||
name: 'adonis-app', | |||
filename: 'adonis.log', | |||
level: 'info' | |||
} | |||
}, | |||
/* | |||
|-------------------------------------------------------------------------- | |||
| Generic Cookie Options | |||
|-------------------------------------------------------------------------- | |||
| | |||
| The following cookie options are generic settings used by AdonisJs to create | |||
| cookies. However, some parts of the application like `sessions` can have | |||
| seperate settings for cookies inside `config/session.js`. | |||
| | |||
*/ | |||
cookie: { | |||
httpOnly: true, | |||
sameSite: false, | |||
path: '/', | |||
maxAge: 7200 | |||
} | |||
} |
@ -0,0 +1,94 @@ | |||
'use strict' | |||
/** @type {import('@adonisjs/framework/src/Env')} */ | |||
const Env = use('Env') | |||
module.exports = { | |||
/* | |||
|-------------------------------------------------------------------------- | |||
| Authenticator | |||
|-------------------------------------------------------------------------- | |||
| | |||
| Authentication is a combination of serializer and scheme with extra | |||
| config to define on how to authenticate a user. | |||
| | |||
| Available Schemes - basic, session, jwt, api | |||
| Available Serializers - lucid, database | |||
| | |||
*/ | |||
authenticator: 'session', | |||
/* | |||
|-------------------------------------------------------------------------- | |||
| Session | |||
|-------------------------------------------------------------------------- | |||
| | |||
| Session authenticator makes use of sessions to authenticate a user. | |||
| Session authentication is always persistent. | |||
| | |||
*/ | |||
session: { | |||
serializer: 'lucid', | |||
model: 'App/Models/User', | |||
scheme: 'session', | |||
uid: 'email', | |||
password: 'password' | |||
}, | |||
/* | |||
|-------------------------------------------------------------------------- | |||
| Basic Auth | |||
|-------------------------------------------------------------------------- | |||
| | |||
| The basic auth authenticator uses basic auth header to authenticate a | |||
| user. | |||
| | |||
| NOTE: | |||
| This scheme is not persistent and users are supposed to pass | |||
| login credentials on each request. | |||
| | |||
*/ | |||
basic: { | |||
serializer: 'lucid', | |||
model: 'App/Models/User', | |||
scheme: 'basic', | |||
uid: 'email', | |||
password: 'password' | |||
}, | |||
/* | |||
|-------------------------------------------------------------------------- | |||
| Jwt | |||
|-------------------------------------------------------------------------- | |||
| | |||
| The jwt authenticator works by passing a jwt token on each HTTP request | |||
| via HTTP `Authorization` header. | |||
| | |||
*/ | |||
jwt: { | |||
serializer: 'lucid', | |||
model: 'App/Models/User', | |||
scheme: 'jwt', | |||
uid: 'email', | |||
password: 'password', | |||
options: { | |||
secret: Env.get('APP_KEY') | |||
} | |||
}, | |||
/* | |||
|-------------------------------------------------------------------------- | |||
| Api | |||
|-------------------------------------------------------------------------- | |||
| | |||
| The Api scheme makes use of API personal tokens to authenticate a user. | |||
| | |||
*/ | |||
api: { | |||
serializer: 'lucid', | |||
model: 'App/Models/User', | |||
scheme: 'api', | |||
uid: 'email', | |||
password: 'password' | |||
} | |||
} |
@ -0,0 +1,157 @@ | |||
'use strict' | |||
module.exports = { | |||
/* | |||
|-------------------------------------------------------------------------- | |||
| JSON Parser | |||
|-------------------------------------------------------------------------- | |||
| | |||
| Below settings are applied when request body contains JSON payload. If | |||
| you want body parser to ignore JSON payload, then simply set `types` | |||
| to an empty array. | |||
*/ | |||
json: { | |||
/* | |||
|-------------------------------------------------------------------------- | |||
| limit | |||
|-------------------------------------------------------------------------- | |||
| | |||
| Defines the limit of JSON that can be sent by the client. If payload | |||
| is over 1mb it will not be processed. | |||
| | |||
*/ | |||
limit: '1mb', | |||
/* | |||
|-------------------------------------------------------------------------- | |||
| strict | |||
|-------------------------------------------------------------------------- | |||
| | |||
| When `scrict` is set to true, body parser will only parse Arrays and | |||
| Object. Otherwise everything parseable by `JSON.parse` is parsed. | |||
| | |||
*/ | |||
strict: true, | |||
/* | |||
|-------------------------------------------------------------------------- | |||
| types | |||
|-------------------------------------------------------------------------- | |||
| | |||
| Which content types are processed as JSON payloads. You are free to | |||
| add your own types here, but the request body should be parseable | |||
| by `JSON.parse` method. | |||
| | |||
*/ | |||
types: [ | |||
'application/json', | |||
'application/json-patch+json', | |||
'application/vnd.api+json', | |||
'application/csp-report' | |||
] | |||
}, | |||
/* | |||
|-------------------------------------------------------------------------- | |||
| Raw Parser | |||
|-------------------------------------------------------------------------- | |||
| | |||
| | |||
| | |||
*/ | |||
raw: { | |||
types: [ | |||
'text/*' | |||
] | |||
}, | |||
/* | |||
|-------------------------------------------------------------------------- | |||
| Form Parser | |||
|-------------------------------------------------------------------------- | |||
| | |||
| | |||
| | |||
*/ | |||
form: { | |||
types: [ | |||
'application/x-www-form-urlencoded' | |||
] | |||
}, | |||
/* | |||
|-------------------------------------------------------------------------- | |||
| Files Parser | |||
|-------------------------------------------------------------------------- | |||
| | |||
| | |||
| | |||
*/ | |||
files: { | |||
types: [ | |||
'multipart/form-data' | |||
], | |||
/* | |||
|-------------------------------------------------------------------------- | |||
| Max Size | |||
|-------------------------------------------------------------------------- | |||
| | |||
| Below value is the max size of all the files uploaded to the server. It | |||
| is validated even before files have been processed and hard exception | |||
| is thrown. | |||
| | |||
| Consider setting a reasonable value here, otherwise people may upload GB's | |||
| of files which will keep your server busy. | |||
| | |||
| Also this value is considered when `autoProcess` is set to true. | |||
| | |||
*/ | |||
maxSize: '20mb', | |||
/* | |||
|-------------------------------------------------------------------------- | |||
| Auto Process | |||
|-------------------------------------------------------------------------- | |||
| | |||
| Whether or not to auto-process files. Since HTTP servers handle files via | |||
| couple of specific endpoints. It is better to set this value off and | |||
| manually process the files when required. | |||
| | |||
| This value can contain a boolean or an array of route patterns | |||
| to be autoprocessed. | |||
*/ | |||
autoProcess: true, | |||
/* | |||
|-------------------------------------------------------------------------- | |||
| Process Manually | |||
|-------------------------------------------------------------------------- | |||
| | |||
| The list of routes that should not process files and instead rely on | |||
| manual process. This list should only contain routes when autoProcess | |||
| is to true. Otherwise everything is processed manually. | |||
| | |||
*/ | |||
processManually: [] | |||
/* | |||
|-------------------------------------------------------------------------- | |||
| Temporary file name | |||
|-------------------------------------------------------------------------- | |||
| | |||
| Define a function, which should return a string to be used as the | |||
| tmp file name. | |||
| | |||
| If not defined, Bodyparser will use `uuid` as the tmp file name. | |||
| | |||
| To be defined as. If you are defining the function, then do make sure | |||
| to return a value from it. | |||
| | |||
| tmpFileName () { | |||
| return 'some-unique-value' | |||
| } | |||
| | |||
*/ | |||
} | |||
} |
@ -0,0 +1,87 @@ | |||
'use strict' | |||
module.exports = { | |||
/* | |||
|-------------------------------------------------------------------------- | |||
| Origin | |||
|-------------------------------------------------------------------------- | |||
| | |||
| Set a list of origins to be allowed. The value can be one of the following | |||
| | |||
| Boolean: true - Allow current request origin | |||
| Boolean: false - Disallow all | |||
| String - Comma seperated list of allowed origins | |||
| Array - An array of allowed origins | |||
| String: * - A wildcard to allow current request origin | |||
| Function - Receives the current origin and should return one of the above values. | |||
| | |||
*/ | |||
origin: false, | |||
/* | |||
|-------------------------------------------------------------------------- | |||
| Methods | |||
|-------------------------------------------------------------------------- | |||
| | |||
| HTTP methods to be allowed. The value can be one of the following | |||
| | |||
| String - Comma seperated list of allowed methods | |||
| Array - An array of allowed methods | |||
| | |||
*/ | |||
methods: ['GET', 'PUT', 'PATCH', 'POST', 'DELETE'], | |||
/* | |||
|-------------------------------------------------------------------------- | |||
| Headers | |||
|-------------------------------------------------------------------------- | |||
| | |||
| List of headers to be allowed via Access-Control-Request-Headers header. | |||
| The value can be on of the following. | |||
| | |||
| Boolean: true - Allow current request headers | |||
| Boolean: false - Disallow all | |||
| String - Comma seperated list of allowed headers | |||
| Array - An array of allowed headers | |||
| String: * - A wildcard to allow current request headers | |||
| Function - Receives the current header and should return one of the above values. | |||
| | |||
*/ | |||
headers: true, | |||
/* | |||
|-------------------------------------------------------------------------- | |||
| Expose Headers | |||
|-------------------------------------------------------------------------- | |||
| | |||
| A list of headers to be exposed via `Access-Control-Expose-Headers` | |||
| header. The value can be on of the following. | |||
| | |||
| Boolean: false - Disallow all | |||
| String: Comma seperated list of allowed headers | |||
| Array - An array of allowed headers | |||
| | |||
*/ | |||
exposeHeaders: false, | |||
/* | |||
|-------------------------------------------------------------------------- | |||
| Credentials | |||
|-------------------------------------------------------------------------- | |||
| | |||
| Define Access-Control-Allow-Credentials header. It should always be a | |||
| boolean. | |||
| | |||
*/ | |||
credentials: false, | |||
/* | |||
|-------------------------------------------------------------------------- | |||
| MaxAge | |||
|-------------------------------------------------------------------------- | |||
| | |||
| Define Access-Control-Allow-Max-Age | |||
| | |||
*/ | |||
maxAge: 90 | |||
} |
@ -0,0 +1,81 @@ | |||
'use strict' | |||
/** @type {import('@adonisjs/framework/src/Env')} */ | |||
const Env = use('Env') | |||
/** @type {import('@adonisjs/ignitor/src/Helpers')} */ | |||
const Helpers = use('Helpers') | |||
module.exports = { | |||
/* | |||
|-------------------------------------------------------------------------- | |||
| Default Connection | |||
|-------------------------------------------------------------------------- | |||
| | |||
| Connection defines the default connection settings to be used while | |||
| interacting with SQL databases. | |||
| | |||
*/ | |||
connection: Env.get('DB_CONNECTION', 'sqlite'), | |||
/* | |||
|-------------------------------------------------------------------------- | |||
| Sqlite | |||
|-------------------------------------------------------------------------- | |||
| | |||
| Sqlite is a flat file database and can be good choice under development | |||
| environment. | |||
| | |||
| npm i --save sqlite3 | |||
| | |||
*/ | |||
sqlite: { | |||
client: 'sqlite3', | |||
connection: { | |||
filename: Helpers.databasePath(`${Env.get('DB_DATABASE', 'development')}.sqlite`) | |||
}, | |||
useNullAsDefault: true | |||
}, | |||
/* | |||
|-------------------------------------------------------------------------- | |||
| MySQL | |||
|-------------------------------------------------------------------------- | |||
| | |||
| Here we define connection settings for MySQL database. | |||
| | |||
| npm i --save mysql | |||
| | |||
*/ | |||
mysql: { | |||
client: 'mysql', | |||
connection: { | |||
host: Env.get('DB_HOST', 'localhost'), | |||
port: Env.get('DB_PORT', ''), | |||
user: Env.get('DB_USER', 'root'), | |||
password: Env.get('DB_PASSWORD', ''), | |||
database: Env.get('DB_DATABASE', 'adonis') | |||
} | |||
}, | |||
/* | |||
|-------------------------------------------------------------------------- | |||
| PostgreSQL | |||
|-------------------------------------------------------------------------- | |||
| | |||
| Here we define connection settings for PostgreSQL database. | |||
| | |||
| npm i --save pg | |||
| | |||
*/ | |||
pg: { | |||
client: 'pg', | |||
connection: { | |||
host: Env.get('DB_HOST', 'localhost'), | |||
port: Env.get('DB_PORT', ''), | |||
user: Env.get('DB_USER', 'root'), | |||
password: Env.get('DB_PASSWORD', ''), | |||
database: Env.get('DB_DATABASE', 'adonis') | |||
} | |||
} | |||
} |
@ -0,0 +1,49 @@ | |||
'use strict' | |||
/** @type {import('@adonisjs/framework/src/Env')} */ | |||
const Env = use('Env') | |||
module.exports = { | |||
/* | |||
|-------------------------------------------------------------------------- | |||
| Driver | |||
|-------------------------------------------------------------------------- | |||
| | |||
| Driver to be used for hashing values. The same driver is used by the | |||
| auth module too. | |||
| | |||
*/ | |||
driver: Env.get('HASH_DRIVER', 'bcrypt'), | |||
/* | |||
|-------------------------------------------------------------------------- | |||
| Bcrypt | |||
|-------------------------------------------------------------------------- | |||
| | |||
| Config related to bcrypt hashing. https://www.npmjs.com/package/bcrypt | |||
| package is used internally. | |||
| | |||
*/ | |||
bcrypt: { | |||
rounds: 10 | |||
}, | |||
/* | |||
|-------------------------------------------------------------------------- | |||
| Argon | |||
|-------------------------------------------------------------------------- | |||
| | |||
| Config related to argon. https://www.npmjs.com/package/argon2 package is | |||
| used internally. | |||
| | |||
| Since argon is optional, you will have to install the dependency yourself | |||
| | |||
|============================================================================ | |||
| npm i argon2 | |||
|============================================================================ | |||
| | |||
*/ | |||
argon: { | |||
type: 1 | |||
} | |||
} |
@ -0,0 +1,95 @@ | |||
'use strict' | |||
/** @type {import('@adonisjs/framework/src/Env')} */ | |||
const Env = use('Env') | |||
module.exports = { | |||
/* | |||
|-------------------------------------------------------------------------- | |||
| Session Driver | |||
|-------------------------------------------------------------------------- | |||
| | |||
| The session driver to be used for storing session values. It can be | |||
| cookie, file or redis. | |||
| | |||
| For `redis` driver, make sure to install and register `@adonisjs/redis` | |||
| | |||
*/ | |||
driver: Env.get('SESSION_DRIVER', 'cookie'), | |||
/* | |||
|-------------------------------------------------------------------------- | |||
| Cookie Name | |||
|-------------------------------------------------------------------------- | |||
| | |||
| The name of the cookie to be used for saving session id. Session ids | |||
| are signed and encrypted. | |||
| | |||
*/ | |||
cookieName: 'adonis-session', | |||
/* | |||
|-------------------------------------------------------------------------- | |||
| Clear session when browser closes | |||
|-------------------------------------------------------------------------- | |||
| | |||
| If this value is true, the session cookie will be temporary and will be | |||
| removed when browser closes. | |||
| | |||
*/ | |||
clearWithBrowser: true, | |||
/* | |||
|-------------------------------------------------------------------------- | |||
| Session age | |||
|-------------------------------------------------------------------------- | |||
| | |||
| This value is only used when `clearWithBrowser` is set to false. The | |||
| age must be a valid https://npmjs.org/package/ms string or should | |||
| be in milliseconds. | |||
| | |||
| Valid values are: | |||
| '2h', '10d', '5y', '2.5 hrs' | |||
| | |||
*/ | |||
age: '2h', | |||
/* | |||
|-------------------------------------------------------------------------- | |||
| Cookie options | |||
|-------------------------------------------------------------------------- | |||
| | |||
| Cookie options defines the options to be used for setting up session | |||
| cookie | |||
| | |||
*/ | |||
cookie: { | |||
httpOnly: true, | |||
sameSite: false, | |||
path: '/' | |||
}, | |||
/* | |||
|-------------------------------------------------------------------------- | |||
| Sessions location | |||
|-------------------------------------------------------------------------- | |||
| | |||
| If driver is set to file, we need to define the relative location from | |||
| the temporary path or absolute url to any location. | |||
| | |||
*/ | |||
file: { | |||
location: 'sessions' | |||
}, | |||
/* | |||
|-------------------------------------------------------------------------- | |||
| Redis config | |||
|-------------------------------------------------------------------------- | |||
| | |||
| The configuration for the redis driver. By default we reference it from | |||
| the redis file. But you are free to define an object here too. | |||
| | |||
*/ | |||
redis: 'self::redis.local' | |||
} |
@ -0,0 +1,145 @@ | |||
'use strict' | |||
module.exports = { | |||
/* | |||
|-------------------------------------------------------------------------- | |||
| Content Security Policy | |||
|-------------------------------------------------------------------------- | |||
| | |||
| Content security policy filters out the origins not allowed to execute | |||
| and load resources like scripts, styles and fonts. There are wide | |||
| variety of options to choose from. | |||
*/ | |||
csp: { | |||
/* | |||
|-------------------------------------------------------------------------- | |||
| Directives | |||
|-------------------------------------------------------------------------- | |||
| | |||
| All directives are defined in camelCase and here is the list of | |||
| available directives and their possible values. | |||
| | |||
| https://content-security-policy.com | |||
| | |||
| @example | |||
| directives: { | |||
| defaultSrc: ['self', '@nonce', 'cdnjs.cloudflare.com'] | |||
| } | |||
| | |||
*/ | |||
directives: { | |||
}, | |||
/* | |||
|-------------------------------------------------------------------------- | |||
| Report only | |||
|-------------------------------------------------------------------------- | |||
| | |||
| Setting `reportOnly=true` will not block the scripts from running and | |||
| instead report them to a URL. | |||
| | |||
*/ | |||
reportOnly: false, | |||
/* | |||
|-------------------------------------------------------------------------- | |||
| Set all headers | |||
|-------------------------------------------------------------------------- | |||
| | |||
| Headers staring with `X` have been depreciated, since all major browsers | |||
| supports the standard CSP header. So its better to disable deperciated | |||
| headers, unless you want them to be set. | |||
| | |||
*/ | |||
setAllHeaders: false, | |||
/* | |||
|-------------------------------------------------------------------------- | |||
| Disable on android | |||
|-------------------------------------------------------------------------- | |||
| | |||
| Certain versions of android are buggy with CSP policy. So you can set | |||
| this value to true, to disable it for Android versions with buggy | |||
| behavior. | |||
| | |||
| Here is an issue reported on a different package, but helpful to read | |||
| if you want to know the behavior. https://github.com/helmetjs/helmet/pull/82 | |||
| | |||
*/ | |||
disableAndroid: true | |||
}, | |||
/* | |||
|-------------------------------------------------------------------------- | |||
| X-XSS-Protection | |||
|-------------------------------------------------------------------------- | |||
| | |||
| X-XSS Protection saves applications from XSS attacks. It is adopted | |||
| by IE and later followed by some other browsers. | |||
| | |||
| Learn more at https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/X-XSS-Protection | |||
| | |||
*/ | |||
xss: { | |||
enabled: true, | |||
enableOnOldIE: false | |||
}, | |||
/* | |||
|-------------------------------------------------------------------------- | |||
| Iframe Options | |||
|-------------------------------------------------------------------------- | |||
| | |||
| xframe defines whether or not your website can be embedded inside an | |||
| iframe. Choose from one of the following options. | |||
| @available options | |||
| DENY, SAMEORIGIN, ALLOW-FROM http://example.com | |||
| | |||
| Learn more at https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/X-Frame-Options | |||
*/ | |||
xframe: 'DENY', | |||
/* | |||
|-------------------------------------------------------------------------- | |||
| No Sniff | |||
|-------------------------------------------------------------------------- | |||
| | |||
| Browsers have a habit of sniffing content-type of a response. Which means | |||
| files with .txt extension containing Javascript code will be executed as | |||
| Javascript. You can disable this behavior by setting nosniff to false. | |||
| | |||
| Learn more at https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/X-Frame-Options | |||
| | |||
*/ | |||
nosniff: true, | |||
/* | |||
|-------------------------------------------------------------------------- | |||
| No Open | |||
|-------------------------------------------------------------------------- | |||
| | |||
| IE users can execute webpages in the context of your website, which is | |||
| a serious security risk. Below option will manage this for you. | |||
| | |||
*/ | |||
noopen: true, | |||
/* | |||
|-------------------------------------------------------------------------- | |||
| CSRF Protection | |||
|-------------------------------------------------------------------------- | |||
| | |||
| CSRF Protection adds another layer of security by making sure, actionable | |||
| routes does have a valid token to execute an action. | |||
| | |||
*/ | |||
csrf: { | |||
enable: true, | |||
methods: ['POST', 'PUT', 'DELETE'], | |||
filterUris: [], | |||
cookieOptions: { | |||
httpOnly: false, | |||
sameSite: true, | |||
path: '/', | |||
maxAge: 7200 | |||
} | |||
} | |||
} |
@ -0,0 +1,21 @@ | |||
'use strict' | |||
/* | |||
|-------------------------------------------------------------------------- | |||
| Factory | |||
|-------------------------------------------------------------------------- | |||
| | |||
| Factories are used to define blueprints for database tables or Lucid | |||
| models. Later you can use these blueprints to seed your database | |||
| with dummy data. | |||
| | |||
*/ | |||
/** @type {import('@adonisjs/lucid/src/Factory')} */ | |||
// const Factory = use('Factory') | |||
// Factory.blueprint('App/Models/User', (faker) => { | |||
// return { | |||
// username: faker.username() | |||
// } | |||
// }) |
@ -0,0 +1,40 @@ | |||
{ | |||
"name": "adonis-fullstack-app", | |||
"version": "0.11.3", | |||
"adonis-version": "4.1.0", | |||
"description": "A video downloader based on youtube-dl", | |||
"main": "index.js", | |||
"scripts": { | |||
"start": "node server.js", | |||
"test": "node ace test" | |||
}, | |||
"keywords": [ | |||
"adonisjs", | |||
"adonis-app" | |||
], | |||
"author": "Loรฏc Bersier", | |||
"license": "", | |||
"private": true, | |||
"dependencies": { | |||
"@adonisjs/ace": "^5.0.8", | |||
"@adonisjs/auth": "^3.0.7", | |||
"@adonisjs/bodyparser": "^2.0.9", | |||
"@adonisjs/cors": "^1.0.7", | |||
"@adonisjs/fold": "^4.0.9", | |||
"@adonisjs/framework": "^5.0.9", | |||
"@adonisjs/ignitor": "^2.0.8", | |||
"@adonisjs/lucid": "^6.1.3", | |||
"@adonisjs/session": "^1.0.27", | |||
"@adonisjs/shield": "^1.0.8", | |||
"@adonisjs/validator": "^5.0.6", | |||
"fluent-ffmpeg": "^2.1.2", | |||
"mysql": "^2.17.1", | |||
"node-fetch": "^2.6.0", | |||
"time-stamp": "^2.2.0", | |||
"youtube-dl": "^1.13.1" | |||
}, | |||
"devDependencies": {}, | |||
"autoload": { | |||
"App": "./app" | |||
} | |||
} |
@ -0,0 +1,99 @@ | |||
/*! | |||
// Snow.js - v0.0.3 | |||
// kurisubrooks.com | |||
*/ | |||
// Amount of Snowflakes | |||
var snowMax = 35; | |||
// Snowflake Colours | |||
var snowColor = ["#DDD", "#EEE"]; | |||
// Snow Entity | |||
var snowEntity = "•"; | |||
// Falling Velocity | |||
var snowSpeed = 1; | |||
// Minimum Flake Size | |||
var snowMinSize = 12; | |||
// Maximum Flake Size | |||
var snowMaxSize = 42; | |||
// Refresh Rate (in milliseconds) | |||
var snowRefresh = 50; | |||
// Additional Styles | |||
var snowStyles = "cursor: default; -webkit-user-select: none; -moz-user-select: none; -ms-user-select: none; -o-user-select: none; user-select: none;"; | |||
/* | |||
// End of Configuration | |||
// ---------------------------------------- | |||
// Do not modify the code below this line | |||
*/ | |||
var snow = [], | |||
pos = [], | |||
coords = [], | |||
lefr = [], | |||
marginBottom, | |||
marginRight; | |||
function randomise(range) { | |||
rand = Math.floor(range * Math.random()); | |||
return rand; | |||
} | |||
function initSnow() { | |||
var snowSize = snowMaxSize - snowMinSize; | |||
marginBottom = document.body.scrollHeight - 5; | |||
marginRight = document.body.clientWidth - 15; | |||
for (i = 0; i <= snowMax; i++) { | |||
coords[i] = 0; | |||
lefr[i] = Math.random() * 15; | |||
pos[i] = 0.03 + Math.random() / 10; | |||
snow[i] = document.getElementById("flake" + i); | |||
snow[i].style.fontFamily = "inherit"; | |||
snow[i].size = randomise(snowSize) + snowMinSize; | |||
snow[i].style.fontSize = snow[i].size + "px"; | |||
snow[i].style.color = snowColor[randomise(snowColor.length)]; | |||
snow[i].style.zIndex = 1000; | |||
snow[i].sink = snowSpeed * snow[i].size / 5; | |||
snow[i].posX = randomise(marginRight - snow[i].size); | |||
snow[i].posY = randomise(2 * marginBottom - marginBottom - 2 * snow[i].size); | |||
snow[i].style.left = snow[i].posX + "px"; | |||
snow[i].style.top = snow[i].posY + "px"; | |||
} | |||
moveSnow(); | |||
} | |||
function resize() { | |||
marginBottom = document.body.scrollHeight - 5; | |||
marginRight = document.body.clientWidth - 15; | |||
} | |||
function moveSnow() { | |||
for (i = 0; i <= snowMax; i++) { | |||
coords[i] += pos[i]; | |||
snow[i].posY += snow[i].sink; | |||
snow[i].style.left = snow[i].posX + lefr[i] * Math.sin(coords[i]) + "px"; | |||
snow[i].style.top = snow[i].posY + "px"; | |||
if (snow[i].posY >= marginBottom - 2 * snow[i].size || parseInt(snow[i].style.left) > (marginRight - 3 * lefr[i])) { | |||
snow[i].posX = randomise(marginRight - snow[i].size); | |||
snow[i].posY = 0; | |||
} | |||
} | |||
setTimeout("moveSnow()", snowRefresh); | |||
} | |||
for (i = 0; i <= snowMax; i++) { | |||
document.write("<span id='flake" + i + "' style='" + snowStyles + "position:absolute;top:-" + snowMaxSize + "'>" + snowEntity + "</span>"); | |||
} | |||
window.addEventListener('resize', resize); | |||
window.addEventListener('load', initSnow); |
@ -0,0 +1,102 @@ | |||
.downloadbtn { | |||
animation: colorchange 13s infinite; | |||
animation-direction: alternate-reverse; | |||
} | |||
a:link { | |||
color: #A0FF9A; | |||
} | |||
a:visited { | |||
color: #A7FF56; | |||
} | |||
a:hover { | |||
color: #DCFFA5 !important; | |||
} | |||
.checkbox:hover, .radio:hover { | |||
color: lightgray !important; | |||
} | |||
.gradientBG { | |||
background: rgb(59,44,207); | |||
background: linear-gradient(90deg, rgba(59,44,207,1) 0%, rgba(140,41,151,1) 100%); | |||
} | |||