Загрузка данных


import os
import socket
from flask import (
    Flask,
    request,
    send_from_directory,
    render_template_string,
    abort,
)
from werkzeug.utils import secure_filename
import qrcode

app = Flask(__name__)

# Максимальный размер загружаемого файла (2 ГБ)
app.config["MAX_CONTENT_LENGTH"] = 2 * 1024 * 1024 * 1024

BASE_DIR = os.path.dirname(os.path.abspath(__file__))

# Файлы, которые нельзя скачать
PROTECTED_FILES = {
    "share.py",
    "gui.py",
    "enter.txt",
    "cert.pem",
    "key.pem",
}

HTML_TEMPLATE = """
<!DOCTYPE html>
<html lang="ru">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Передача на ПК</title>
    <style>
        body {
            font-family: sans-serif;
            padding: 20px;
            max-width: 600px;
            margin: 0 auto;
            background: #f4f4f9;
        }

        .card {
            background: white;
            padding: 20px;
            border-radius: 8px;
            box-shadow: 0 2px 5px rgba(0,0,0,.1);
            margin-bottom: 20px;
        }

        textarea,
        input[type=file],
        input[type=submit] {
            width: 100%;
            margin-top: 10px;
            box-sizing: border-box;
        }

        textarea {
            height: 120px;
        }

        input[type=submit] {
            padding: 12px;
            background: #28a745;
            color: white;
            border: none;
            border-radius: 4px;
            cursor: pointer;
            font-size: 16px;
        }

        ul {
            list-style: none;
            padding: 0;
        }

        li {
            margin: 8px 0;
        }

        a {
            color: #007bff;
            text-decoration: none;
        }
    </style>
</head>

<body>

<div class="card">
    <h3>Отправить текст на ПК</h3>

    <form action="/send_text" method="post">
        <textarea
            name="text"
            placeholder="Введите или вставьте текст..."
        ></textarea>

        <input
            type="submit"
            value="Сохранить в enter.txt"
        >
    </form>
</div>

<div class="card">

    <h3>Отправить файл на ПК</h3>

    <form
        action="/upload_file"
        method="post"
        enctype="multipart/form-data"
    >

        <input
            type="file"
            name="file"
        >

        <input
            type="submit"
            value="Загрузить файл"
        >

    </form>

</div>

<div class="card">

<h3>Файлы на сервере</h3>

<ul>

{% for file in files %}

<li>

<a href="/download/{{ file }}" download>

{{ file }}

</a>

</li>

{% endfor %}

</ul>

</div>

</body>
</html>
"""

def get_local_ip():
    s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)

    try:
        s.connect(("10.255.255.255", 1))
        ip = s.getsockname()[0]
    except Exception:
        ip = "127.0.0.1"
    finally:
        s.close()

    return ip


@app.route("/")
def index():

    files = []

    for f in os.listdir(BASE_DIR):

        path = os.path.join(BASE_DIR, f)

        if (
            os.path.isfile(path)
            and not f.startswith(".")
            and f not in PROTECTED_FILES
        ):
            files.append(f)

    files.sort()

    return render_template_string(
        HTML_TEMPLATE,
        files=files,
    )


@app.route("/send_text", methods=["POST"])
def receive_text():

    text = request.form.get("text", "")

    if text:

        text = (
            text.replace("\r\n", "\n")
            .replace("\r", "\n")
            .strip()
        )

        text = text.replace("\n", "\r\n")

        with open(
            os.path.join(BASE_DIR, "enter.txt"),
            "a",
            encoding="utf-8",
            newline=""
        ) as f:

            f.write(text + "\r\n---\r\n")
    return index()


@app.route("/upload_file", methods=["POST"])
def receive_file():

    if "file" not in request.files:
        return index()

    file = request.files["file"]

    if file.filename == "":
        return index()

    # Безопасное имя файла
    filename = secure_filename(file.filename)
    filename = os.path.basename(filename)

    if not filename:
        return index()

    filepath = os.path.join(BASE_DIR, filename)

    # Автоматическое переименование
    name, ext = os.path.splitext(filename)
    counter = 1

    while os.path.exists(filepath):
        filename = f"{name} ({counter}){ext}"
        filepath = os.path.join(BASE_DIR, filename)
        counter += 1

    file.save(filepath)

    return index()


@app.route("/download/<path:filename>")
def download_file(filename):

    filename = os.path.basename(filename)

    # Запрет скрытых файлов
    if filename.startswith("."):
        abort(403)

    # Запрет защищённых файлов
    if filename in PROTECTED_FILES:
        abort(403)

    filepath = os.path.join(BASE_DIR, filename)

    if not os.path.isfile(filepath):
        abort(404)

    return send_from_directory(
        BASE_DIR,
        filename,
        as_attachment=True
    )


if __name__ == "__main__":

    port = 5000
    ip = get_local_ip()

    # HTTPS при наличии сертификатов
    cert_file = os.path.join(BASE_DIR, "cert.pem")
    key_file = os.path.join(BASE_DIR, "key.pem")

    ssl_context = None

    if (
        os.path.exists(cert_file)
        and
        os.path.exists(key_file)
    ):
        ssl_context = (cert_file, key_file)
        protocol = "https"
    else:
        protocol = "http"

    url = f"{protocol}://{ip}:{port}"

    qr = qrcode.QRCode()
    qr.add_data(url)
    qr.make(fit=True)

    print(f"\nСервер запущен.\n")
    print(f"Адрес: {url}\n")

    qr.print_ascii(invert=True)

    app.run(
        host="0.0.0.0",
        port=port,
        ssl_context=ssl_context
    )