|
#! /usr/bin/env python3 |
|
from flask import Flask, request, send_file, abort |
|
from os import walk, sep, makedirs, getpid |
|
from os.path import exists, basename |
|
from werkzeug.utils import secure_filename |
|
from subprocess import Popen |
|
|
|
app = Flask(__name__) |
|
|
|
|
|
@app.route('/', methods=['GET', 'POST']) |
|
def index(): |
|
new_files = [] |
|
message = '' |
|
errors = '' |
|
if request.method == 'POST': |
|
count = 0 |
|
dirscreated = 0 |
|
errcount = 0 |
|
for file in request.files.getlist('files') + request.files.getlist('folders'): |
|
name = file.filename.replace('/..', '_') |
|
try: |
|
try: |
|
file.save(name) |
|
new_files.append(name) |
|
except FileNotFoundError: |
|
if sep not in name: |
|
raise |
|
path, _ = name.rsplit(sep, 1) |
|
makedirs(path) |
|
file.save(name) |
|
new_files.append(name.rsplit(sep, 1)[1]) |
|
dirscreated += name.count(sep) |
|
except Exception as e: |
|
errors += f'<li>{file.filename} → <tt>{type(e).__name__}: {e!s}</tt></li>\n' |
|
errcount += 1 |
|
else: |
|
count += 1 |
|
if count > 0: |
|
message += f'{count} files uploaded. ' |
|
if dirscreated > 0: |
|
message += f'{dirscreated} folders created. ' |
|
if errors: |
|
errors = f'<details class="err"><summary>{errcount} errors</summary><ul>{errors}</ul></details>' |
|
files_list = '' |
|
tab = '<span class="bar">|</span> ' |
|
for root, dirs, files in walk('.'): |
|
tabs = root.count(sep) |
|
folder = basename(root) |
|
if not folder: |
|
folder = root[:-1] |
|
else: |
|
tabs += 1 |
|
folder = folder.replace('/./', '/') |
|
files_list += f'{tab*(tabs-1)}{folder}/\n' |
|
tabs += 1 |
|
for file in files: |
|
files_list += f'{tab*(tabs-1)}<a href="/{folder}/{file}" download="{file}"' |
|
if file in new_files: |
|
files_list += ' class="hl"' |
|
files_list += f'>{file}</a>\n' |
|
return f''' |
|
<!DOCTYPE html><html><head><title>Airdrop</title> |
|
<style>.hl{{background-color:yellow}}.err{{color:red}}details{{border:1px solid red}}.bar{{opacity:50%}}</style></head> |
|
<body> |
|
<form action="/" enctype="multipart/form-data" method="POST"> |
|
Folders: <input type="file" name="files" multiple directory webkitdirectory></input><br> |
|
Files: <input type="file" name="folders" multiple></input><br> |
|
<input type="submit" value="Upload"></input> |
|
</form> |
|
<p><a href="/__EXIT__">Stop server</a></p> |
|
{errors} |
|
<p class="hl">{message}</p> |
|
<pre>{files_list}</pre> |
|
</body></html>''' |
|
|
|
|
|
@app.route('/favicon.ico') |
|
def icon(): |
|
abort(404) |
|
|
|
|
|
@app.route('/<path:path>') |
|
def send(path): |
|
return send_file(path.lstrip('/')) |
|
|
|
@app.route('/__EXIT__') |
|
def stop(): |
|
Popen(["sh", "-c", f"sleep 0.75; kill {getpid()}"]) |
|
return """<!DOCTYPE html><html> |
|
<head><meta http-equiv="refresh" content="1; url=/" /></head> |
|
<body><h1>Server stopped.</h1></body></html>""" |
|
|
|
|
|
if __name__ == '__main__': |
|
app.run('192.168.1.158', 4443) |