├── middleware
└── .gitkeep
├── log
└── .gitignore
├── static
├── css
│ └── .gitignore
├── img
│ ├── bg.jpg
│ ├── qrcode.jpg
│ ├── texture.png
│ ├── download.svg
│ ├── github.svg
│ ├── error.svg
│ └── 404.svg
├── scss
│ ├── _footer_mobile.scss
│ ├── _footer.scss
│ ├── icon.scss
│ ├── _header_mobile.scss
│ ├── _uploader_mobile.scss
│ ├── status.scss
│ ├── global.scss
│ ├── _header.scss
│ ├── share.scss
│ └── _uploader.scss
├── font
│ └── 2fcrYFNaTjcS6g4U3t-Y5ZjZjT5FdEJ140U2DJYC3mY.woff2
└── js
│ ├── share.js
│ ├── status.js
│ └── index.js
├── data
├── database
│ └── .gitignore
└── upload
│ └── .gitignore
├── .gitignore
├── _design
└── texture.psd
├── config.js
├── view
├── components
│ ├── uploader_text.ejs
│ ├── uploader_error.ejs
│ ├── head.ejs
│ ├── uploader_progress.ejs
│ ├── footer.ejs
│ ├── header.ejs
│ ├── uploader_file.ejs
│ ├── history-panel.ejs
│ ├── status.ejs
│ ├── uploader.ejs
│ ├── uploader_result.ejs
│ └── share.ejs
├── share.ejs
├── status.ejs
└── index.ejs
├── router
├── index.js
├── status.js
├── delete.js
├── refresh.js
├── share.js
├── download.js
├── upload.js
├── router.js
└── update.js
├── tool
├── log4js.js
├── info.js
├── gc.js
└── sequelize.js
├── ChangeLog.md
├── LICENSE
├── package.json
├── app.js
├── cmd
└── local.js
├── README.md
└── yarn.lock
/middleware/.gitkeep:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/log/.gitignore:
--------------------------------------------------------------------------------
1 | *
2 | !.gitignore
--------------------------------------------------------------------------------
/static/css/.gitignore:
--------------------------------------------------------------------------------
1 | *.css
2 |
--------------------------------------------------------------------------------
/data/database/.gitignore:
--------------------------------------------------------------------------------
1 | *
2 | !.gitignore
--------------------------------------------------------------------------------
/data/upload/.gitignore:
--------------------------------------------------------------------------------
1 | *
2 | !.gitignore
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | node_modules
2 | .vscode
3 | !.gitkeep
4 | _design
--------------------------------------------------------------------------------
/static/img/bg.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/delbertbeta/rajio/HEAD/static/img/bg.jpg
--------------------------------------------------------------------------------
/_design/texture.psd:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/delbertbeta/rajio/HEAD/_design/texture.psd
--------------------------------------------------------------------------------
/static/img/qrcode.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/delbertbeta/rajio/HEAD/static/img/qrcode.jpg
--------------------------------------------------------------------------------
/static/img/texture.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/delbertbeta/rajio/HEAD/static/img/texture.png
--------------------------------------------------------------------------------
/config.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | domain: "https://rajio.delbertbeta.cc",
3 | maxFileSize: 128 * 1000 * 1000 // 128MB
4 | }
5 |
--------------------------------------------------------------------------------
/static/scss/_footer_mobile.scss:
--------------------------------------------------------------------------------
1 | @media(max-width: 500px) {
2 | .footer {
3 | height: 4rem;
4 | padding: 1rem 1rem;
5 | margin-bottom: 1rem;
6 | }
7 | }
--------------------------------------------------------------------------------
/static/font/2fcrYFNaTjcS6g4U3t-Y5ZjZjT5FdEJ140U2DJYC3mY.woff2:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/delbertbeta/rajio/HEAD/static/font/2fcrYFNaTjcS6g4U3t-Y5ZjZjT5FdEJ140U2DJYC3mY.woff2
--------------------------------------------------------------------------------
/view/components/uploader_text.ejs:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | | Name |
7 | Download |
8 | Upload Time |
9 | Delete |
10 |
11 |
12 |
13 |
14 |
Oops! Empty here.
15 |
16 |
--------------------------------------------------------------------------------
/view/components/status.ejs:
--------------------------------------------------------------------------------
1 |
2 |
<%= data %>
3 |
4 |
9 | <%- include uploader_file.ejs -%>
10 | <%- include uploader_text.ejs -%>
11 |
12 |
13 | <%- include uploader_progress.ejs -%>
14 |
15 |
16 | <%- include uploader_result.ejs -%>
17 |
18 |
19 | <%- include uploader_error.ejs -%>
20 |
21 |
--------------------------------------------------------------------------------
/static/scss/_header_mobile.scss:
--------------------------------------------------------------------------------
1 | @media(max-width: 500px){
2 | .header {
3 | height: 4rem;
4 | padding: 1rem 5%;
5 | .header-icon {
6 | font-size: 2rem;
7 | }
8 | .header-title {
9 | font-size: 2rem;
10 | }
11 | .header-expaination {
12 | font-size: 1rem;
13 | }
14 | .history-entry {
15 | bottom: 0.5rem;
16 | }
17 | }
18 |
19 | .history-panel {
20 | height: 60vh;
21 | width: 95vw;
22 | top: 8vh;
23 | left: 2.5vw;
24 | .renew-button {
25 | margin-top: 6px;
26 | }
27 | .table-wrapper::-webkit-scrollbar {
28 | width: 2px;
29 | }
30 | .table-wrapper::-webkit-scrollbar-track {
31 | border-radius: 2px;
32 | }
33 | .table-wrapper::-webkit-scrollbar-thumb {
34 | border-radius: 2px;
35 | }
36 | .table-wrapper {
37 | height: 51vh;
38 | overflow-x: auto;
39 | }
40 | }
41 | }
--------------------------------------------------------------------------------
/tool/info.js:
--------------------------------------------------------------------------------
1 | const diskusage = require('diskusage')
2 | const sequelize = require('../tool/sequelize')
3 | const cron = require('node-cron')
4 |
5 | const getUsage = () => diskusage.checkSync(__dirname)
6 |
7 | const getDownloadCount = async () => {
8 | const result = await sequelize.rajio.sum('downloadCount')
9 | return result
10 | }
11 |
12 | const getTotalCount = async () => {
13 | const result = await sequelize.rajio.count()
14 | return result
15 | }
16 |
17 | const getRecent = async () => {
18 | const result = await sequelize.rajioInfo.findAll({
19 | limit: 7
20 | })
21 | return result
22 | }
23 |
24 | const init = () => {
25 | sequelize.rajioInfo.create().catch(e => {})
26 | cron.schedule('0 0 * * *', () => {
27 | sequelize.rajioInfo.create().catch(e => {})
28 | })
29 | }
30 |
31 | module.exports = {
32 | getUsage,
33 | getDownloadCount,
34 | getTotalCount,
35 | getRecent,
36 | init
37 | }
--------------------------------------------------------------------------------
/router/share.js:
--------------------------------------------------------------------------------
1 | const sequelize = require('../tool/sequelize')
2 | const prettyBytes = require('pretty-bytes')
3 | const moment = require('moment')
4 |
5 | module.exports = async (ctx) => {
6 | const item = await sequelize.rajio.findOne({
7 | where: {
8 | downloadCode: ctx.code
9 | }
10 | })
11 | let forbidden = false
12 | if (!item || item.deleted) {
13 | forbidden = true
14 | ctx.response.status = 404
15 | } else {
16 | item.fileSize = prettyBytes(item.fileSize)
17 | const now = moment()
18 | const limit = moment(item.timeLimit)
19 | if ((item.downloadLimit !== null && item.downloadLimit <= item.downloadCount) || (item.timeLimit !== null && now.isAfter(limit, 'second'))) {
20 | forbidden = true
21 | ctx.response.status = 404
22 | }
23 | }
24 |
25 | await ctx.render('share', {
26 | share: true,
27 | item: item,
28 | domain: global.config.domain,
29 | forbidden
30 | });
31 | }
--------------------------------------------------------------------------------
/tool/gc.js:
--------------------------------------------------------------------------------
1 | const cron = require('node-cron')
2 | const sequelize = require('../tool/sequelize')
3 | const fs = require('fs-extra')
4 | const path = require('path')
5 | const Sequelize = require('sequelize')
6 |
7 | const Op = require('sequelize').Op
8 |
9 | const garbageCollection = async () => {
10 | const garbages = await sequelize.rajio.findAll({
11 | where: {
12 | [Op.or]: {
13 | "downloadCount": {
14 | [Op.gte]: Sequelize.col('downloadLimit')
15 | },
16 | "timeLimit": {
17 | [Op.lte]: new Date()
18 | }
19 | },
20 | "deleted": {
21 | [Op.not]: true
22 | }
23 | }
24 | })
25 | garbages.forEach(v => {
26 | v.deleted = true
27 | fs.removeSync(path.resolve(`./data/upload/${v.id}`))
28 | v.save()
29 | })
30 | }
31 |
32 | module.exports = {
33 | init: () => {
34 | cron.schedule('*/15 * * * *', garbageCollection)
35 | },
36 | recycle: (item) => {
37 | item.deleted = true
38 | item.save()
39 | fs.removeSync(path.resolve(`./data/upload/${item.id}`))
40 | }
41 | }
42 |
43 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2018 delbertbeta
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/view/components/uploader_result.ejs:
--------------------------------------------------------------------------------
1 |