Skip to content

Commit 30cbf6f

Browse files
committed
nanabox
0 parents  commit 30cbf6f

15 files changed

+1527
-0
lines changed

.github/FUNDING.yaml

+1
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
patreon: axorax

LICENSE

+21
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
MIT License
2+
3+
Copyright (c) 2023 Axorax
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.

README.md

+41
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
![Thumbnail](./thumbnail.png)
2+
3+
## ✨ · Installation
4+
5+
Latest version: `1.0.0`
6+
7+
### 💫 Executable file:
8+
9+
1. Go to https://github.com/Axorax/nanabox/releases
10+
11+
2. Download a file according to your operating system.
12+
13+
### 🐍 With Python:
14+
15+
1. Download the source code or run (in terminal):
16+
17+
```
18+
git clone https://github.com/Axorax/nanabox.git
19+
```
20+
21+
2. In terminal, run:
22+
23+
```
24+
pip install -r requirements.txt
25+
```
26+
27+
3. Finally, run:
28+
29+
```sh
30+
python main.py
31+
```
32+
33+
## ❎ · File not uploading!
34+
35+
> [!IMPORTANT]
36+
> Nanabox uses other free APIs to store the uploaded files. You can change the API being used by clicking on `Select host` and changing it. Sometimes the APIs may go down then it won't work.
37+
38+
---
39+
40+
[Support me on Patreon](https://www.patreon.com/axorax)
41+
[Check out my socials](https://github.com/axorax/socials)

build.bat

+3
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
@echo off
2+
pyinstaller --name="nanabox" --onefile --paths=env\Lib\site-packages --add-data="static;static" --add-data="templates;templates" main.py --noconsole --icon=static/nanabox.ico
3+
pause

build.ps1

+1
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
pyinstaller --name "nanabox" --onefile --paths env\Lib\site-packages --add-data "static;static" --add-data "templates;templates" main.py --noconsole --icon static\nanabox.ico

build.sh

+3
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
#!/bin/bash
2+
3+
pyinstaller --name="nanabox" --onefile --paths=env/Lib/site-packages --add-data="static:static" --add-data="templates:templates" main.py --noconsole --icon=static/nanabox.ico

main.py

+208
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,208 @@
1+
from flask import Flask
2+
from flask import render_template
3+
from flask import request
4+
from flask import jsonify
5+
from flaskwebgui import FlaskUI
6+
import requests
7+
import json
8+
import concurrent.futures
9+
import multiprocessing
10+
import sys
11+
import logging
12+
13+
# Set to "False" when debugging then
14+
# it will output to the terminal
15+
16+
IN_APP_LOGS = True
17+
18+
class OutputCapturer:
19+
output = []
20+
21+
def __enter__(self):
22+
self._stdout = sys.stdout
23+
self._stderr = sys.stderr
24+
sys.stdout = self
25+
sys.stderr = self
26+
return self
27+
28+
def __exit__(self, exc_type, exc_val, exc_tb):
29+
sys.stdout = self._stdout
30+
sys.stderr = self._stderr
31+
32+
def write(self, text):
33+
self.output.append(text)
34+
35+
def flush(self):
36+
pass
37+
38+
app = Flask(__name__)
39+
40+
try:
41+
with open('nanabox.json', 'r') as file:
42+
json_file = json.load(file)
43+
except (FileNotFoundError, json.JSONDecodeError):
44+
json_file = {
45+
"hosts": {
46+
"fileio": {
47+
"url": "https://file.io",
48+
"link": "lambda data: data['link']"
49+
},
50+
"anon": {
51+
"url": "https://api.anonfiles.com/upload",
52+
"link": "lambda data: data['data']['file']['url']['short']"
53+
},
54+
"filechan": {
55+
"url": "https://api.filechan.org/upload",
56+
"link": "lambda data: data['data']['file']['url']['short']"
57+
},
58+
"myfile": {
59+
"url": "https://api.myfile.is/upload",
60+
"link": "lambda data: data['data']['file']['url']['short']"
61+
},
62+
"bay": {
63+
"url": "https://api.bayfiles.com/upload",
64+
"link": "lambda data: data['data']['file']['url']['short']"
65+
},
66+
"letsupload": {
67+
"url": "https://api.letsupload.cc/upload",
68+
"link": "lambda data: data['data']['file']['url']['short']"
69+
}
70+
},
71+
"history": {}
72+
}
73+
74+
def fileio(data):
75+
return data["link"]
76+
77+
hosts = json_file["hosts"]
78+
79+
def evaluate_function_string(func_str):
80+
def dynamic_function(data):
81+
return eval(func_str)
82+
return dynamic_function
83+
84+
for key, value in hosts.items():
85+
if isinstance(value, str):
86+
hosts[key] = evaluate_function_string(value)
87+
88+
@app.route('/')
89+
def home():
90+
return render_template('index.html')
91+
92+
# GET | Backend logs
93+
94+
@app.route('/logs')
95+
def send_logs():
96+
filtered_output = [line.decode() if isinstance(line, bytes) else line for line in OutputCapturer.output if line.strip()]
97+
return jsonify({'output': filtered_output})
98+
99+
# POST | Upload file(s)
100+
101+
def upload_file(url, file):
102+
with requests.post(url, files={'file': (file.filename, file.read())}) as response:
103+
return response.json()
104+
105+
@app.route('/upload', methods=['POST'])
106+
def upload():
107+
try:
108+
if 'file' not in request.files:
109+
print("[ERROR] No file provided")
110+
return jsonify({"error": "No file provided"}), 400
111+
112+
file = request.files['file']
113+
114+
if file.filename == '':
115+
print("[ERROR] No file selected")
116+
return jsonify({"error": "No file selected"}), 400
117+
118+
host = hosts.get(request.args.get('host'))
119+
url = host['url']
120+
121+
if not url:
122+
print("[ERROR] Invalid host!")
123+
return jsonify({"error": "Invalid host"}), 400
124+
125+
result_queue = multiprocessing.Queue()
126+
127+
with concurrent.futures.ThreadPoolExecutor() as executor:
128+
future = executor.submit(upload_file, url, file)
129+
future.add_done_callback(lambda future: result_queue.put(future.result()))
130+
131+
data = result_queue.get()
132+
print("[SUCCESS] DATA RECEIVED: " + json.dumps(data))
133+
134+
file_link_fn_str = host['link']
135+
file_link = eval(file_link_fn_str)(data)
136+
file_name = file.filename
137+
138+
json_file["history"][file_name] = file_link
139+
140+
with open('nanabox.json', 'w') as file:
141+
json.dump(json_file, file)
142+
143+
return jsonify({
144+
"Link": file_link
145+
})
146+
except Exception as err:
147+
print(str(err))
148+
return jsonify({
149+
"error": "Host may be down! (check logs for more info)"
150+
})
151+
152+
# POST | Add host
153+
154+
@app.route('/add-host/<name>', methods=['POST'])
155+
def addHost(name):
156+
try:
157+
data = request.json
158+
json_file["hosts"][name] = data.get('get_link_from_json')
159+
160+
with open('nanabox.json', 'w') as file:
161+
json.dump(json_file, file)
162+
except Exception as err:
163+
print(str(err))
164+
return jsonify({
165+
"error": "Failed to add host!"
166+
})
167+
168+
# GET | Upload history
169+
170+
@app.route('/history', methods=['GET'])
171+
def send_history():
172+
try:
173+
with open('nanabox.json', 'r') as file:
174+
data = json.load(file)
175+
return jsonify(data["history"])
176+
except (FileNotFoundError, json.JSONDecodeError):
177+
return jsonify(["error"]), 404
178+
179+
# POST | Clear file upload history
180+
181+
@app.route('/clear', methods=['DELETE'])
182+
def clear_history():
183+
with open('nanabox.json', 'r+') as file:
184+
data = json.load(file)
185+
data["history"] = {}
186+
file.seek(0)
187+
json.dump(data, file)
188+
file.truncate()
189+
190+
return jsonify({"success": True})
191+
192+
# GET | Array of all hosts
193+
194+
@app.route('/hosts', methods=['GET'])
195+
def send_hosts():
196+
return jsonify(list(hosts.keys()))
197+
198+
if __name__ == '__main__':
199+
if (IN_APP_LOGS):
200+
app.logger.addHandler(logging.StreamHandler(sys.stderr))
201+
app.logger.setLevel(logging.INFO)
202+
203+
with OutputCapturer() as capturer:
204+
# app.run(debug=True)
205+
FlaskUI(app=app, server="flask", width=400, height=500).run()
206+
else:
207+
# app.run(debug=True)
208+
FlaskUI(app=app, server="flask", width=400, height=500).run()

requirements.txt

+16
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
blinker==1.6.2
2+
certifi==2023.7.22
3+
charset-normalizer==3.2.0
4+
click==8.1.6
5+
colorama==0.4.6
6+
Flask==2.3.2
7+
flaskwebgui==1.0.6
8+
idna==3.4
9+
itsdangerous==2.1.2
10+
Jinja2==3.1.2
11+
MarkupSafe==2.1.3
12+
psutil==5.9.5
13+
requests==2.31.0
14+
urllib3==2.0.4
15+
Werkzeug==2.3.6
16+
pyinstaller==6.2.0

0 commit comments

Comments
 (0)